mirror of
https://github.com/Dokploy/website
synced 2025-06-26 18:16:01 +00:00
feat: enhance blog post page with markdown rendering and related posts
This commit is contained in:
@@ -5,6 +5,11 @@ import { getTranslations } from "next-intl/server";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { notFound } from "next/navigation";
|
||||
import type { DetailedHTMLProps, HTMLAttributes } from "react";
|
||||
import ReactMarkdown from "react-markdown";
|
||||
import type { Components } from "react-markdown";
|
||||
import rehypeRaw from "rehype-raw";
|
||||
import remarkGfm from "remark-gfm";
|
||||
|
||||
type Props = {
|
||||
params: { locale: string; slug: string };
|
||||
@@ -52,6 +57,10 @@ export default async function BlogPostPage({ params }: Props) {
|
||||
const { locale, slug } = params;
|
||||
const t = await getTranslations({ locale, namespace: "blog" });
|
||||
const post = await getPost(slug);
|
||||
const allPosts = await getPosts();
|
||||
|
||||
// Get related posts (excluding current post)
|
||||
const relatedPosts = allPosts.filter((p) => p.id !== post?.id).slice(0, 3); // Show only 3 related posts
|
||||
|
||||
if (!post) {
|
||||
notFound();
|
||||
@@ -63,6 +72,50 @@ export default async function BlogPostPage({ params }: Props) {
|
||||
day: "numeric",
|
||||
});
|
||||
|
||||
const components: Partial<Components> = {
|
||||
h1: ({ node, ...props }) => (
|
||||
<h1 className="text-3xl font-bold mt-8 mb-4" {...props} />
|
||||
),
|
||||
h2: ({ node, ...props }) => (
|
||||
<h2 className="text-2xl font-bold mt-6 mb-3" {...props} />
|
||||
),
|
||||
h3: ({ node, ...props }) => (
|
||||
<h3 className="text-xl font-bold mt-4 mb-2" {...props} />
|
||||
),
|
||||
p: ({ node, ...props }) => (
|
||||
<p className="text-base leading-relaxed mb-4" {...props} />
|
||||
),
|
||||
a: ({ node, href, ...props }) => (
|
||||
<a
|
||||
href={href}
|
||||
className="text-primary hover:text-primary/80 transition-colors"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
{...props}
|
||||
/>
|
||||
),
|
||||
ul: ({ node, ...props }) => (
|
||||
<ul className="list-disc list-inside space-y-2 mb-4" {...props} />
|
||||
),
|
||||
ol: ({ node, ...props }) => (
|
||||
<ol className="list-decimal list-inside space-y-2 mb-4" {...props} />
|
||||
),
|
||||
li: ({ node, ...props }) => (
|
||||
<li className="text-base leading-relaxed" {...props} />
|
||||
),
|
||||
blockquote: ({ node, ...props }) => (
|
||||
<blockquote
|
||||
className="border-l-4 border-primary pl-4 py-2 my-4 bg-muted/50"
|
||||
{...props}
|
||||
/>
|
||||
),
|
||||
img: ({ node, src, alt }) => (
|
||||
<div className="relative w-full h-64 my-6 rounded-lg overflow-hidden">
|
||||
<Image src={src || ""} alt={alt || ""} fill className="object-cover" />
|
||||
</div>
|
||||
),
|
||||
};
|
||||
|
||||
return (
|
||||
<article className="container mx-auto px-4 py-12 max-w-4xl">
|
||||
<Link
|
||||
@@ -84,59 +137,115 @@ export default async function BlogPostPage({ params }: Props) {
|
||||
{t("backToBlog")}
|
||||
</Link>
|
||||
|
||||
<header className="mb-8">
|
||||
<h1 className="text-4xl font-bold mb-4">{post.title}</h1>
|
||||
<div className="flex items-center mb-6">
|
||||
{post.primary_author?.profile_image && (
|
||||
<div className="relative h-12 w-12 rounded-full overflow-hidden mr-4">
|
||||
<div className="bg-card rounded-lg p-8 shadow-lg border border-border">
|
||||
<header className="mb-8">
|
||||
<h1 className="text-4xl font-bold mb-4">{post.title}</h1>
|
||||
<div className="flex items-center mb-6">
|
||||
{post.primary_author?.profile_image && (
|
||||
<div className="relative h-12 w-12 rounded-full overflow-hidden mr-4">
|
||||
<Image
|
||||
src={post.primary_author.profile_image}
|
||||
alt={post.primary_author.name}
|
||||
fill
|
||||
className="object-cover"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<p className="font-medium">
|
||||
{post.primary_author?.name || "Unknown Author"}
|
||||
</p>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{formattedDate} • {post.reading_time} min read
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{post.feature_image && (
|
||||
<div className="relative h-96 w-full rounded-lg overflow-hidden mb-8">
|
||||
<Image
|
||||
src={post.primary_author.profile_image}
|
||||
alt={post.primary_author.name}
|
||||
src={post.feature_image}
|
||||
alt={post.title}
|
||||
fill
|
||||
className="object-cover"
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<p className="font-medium">
|
||||
{post.primary_author?.name || "Unknown Author"}
|
||||
</p>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{formattedDate} • {post.reading_time} min read
|
||||
</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div className="prose prose-lg max-w-none">
|
||||
<ReactMarkdown
|
||||
remarkPlugins={[remarkGfm]}
|
||||
rehypePlugins={[rehypeRaw]}
|
||||
components={components}
|
||||
>
|
||||
{post.html}
|
||||
</ReactMarkdown>
|
||||
</div>
|
||||
{post.feature_image && (
|
||||
<div className="relative h-96 w-full rounded-lg overflow-hidden">
|
||||
<Image
|
||||
src={post.feature_image}
|
||||
alt={post.title}
|
||||
fill
|
||||
className="object-cover"
|
||||
priority
|
||||
/>
|
||||
|
||||
{post.tags && post.tags.length > 0 && (
|
||||
<div className="mt-12 pt-6 border-t border-border">
|
||||
<h2 className="text-xl font-semibold mb-4">{t("tags")}</h2>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{post.tags.map((tag) => (
|
||||
<Link
|
||||
key={tag.id}
|
||||
href={`/blog/tag/${tag.slug}`}
|
||||
className="px-4 py-2 bg-muted hover:bg-muted/80 rounded-full text-sm transition-colors"
|
||||
>
|
||||
{tag.name}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</header>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="prose prose-lg max-w-none prose-headings:text-foreground prose-a:text-primary hover:prose-a:text-primary/80"
|
||||
dangerouslySetInnerHTML={{ __html: post.html }}
|
||||
/>
|
||||
{relatedPosts.length > 0 && (
|
||||
<div className="mt-12">
|
||||
<h2 className="text-2xl font-bold mb-6">{t("relatedPosts")}</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
{relatedPosts.map((relatedPost) => {
|
||||
const relatedPostDate = new Date(
|
||||
relatedPost.published_at,
|
||||
).toLocaleDateString(locale, {
|
||||
year: "numeric",
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
});
|
||||
|
||||
{post.tags && post.tags.length > 0 && (
|
||||
<div className="mt-12 pt-6 border-t border-border">
|
||||
<h2 className="text-xl font-semibold mb-4">{t("tags")}</h2>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{post.tags.map((tag) => (
|
||||
<Link
|
||||
key={tag.id}
|
||||
href={`/blog/tag/${tag.slug}`}
|
||||
className="px-4 py-2 bg-muted hover:bg-muted/80 rounded-full text-sm transition-colors"
|
||||
>
|
||||
{tag.name}
|
||||
</Link>
|
||||
))}
|
||||
return (
|
||||
<Link
|
||||
key={relatedPost.id}
|
||||
href={`/blog/${relatedPost.slug}`}
|
||||
className="group"
|
||||
>
|
||||
<div className="bg-card rounded-lg overflow-hidden h-full shadow-lg transition-all duration-300 hover:shadow-xl border border-border">
|
||||
{relatedPost.feature_image && (
|
||||
<div className="relative h-48 w-full">
|
||||
<Image
|
||||
src={relatedPost.feature_image}
|
||||
alt={relatedPost.title}
|
||||
fill
|
||||
className="object-cover"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className="p-6">
|
||||
<h3 className="text-lg font-semibold mb-2 group-hover:text-primary transition-colors line-clamp-2">
|
||||
{relatedPost.title}
|
||||
</h3>
|
||||
<p className="text-sm text-muted-foreground mb-4">
|
||||
{relatedPostDate} • {relatedPost.reading_time} min read
|
||||
</p>
|
||||
<p className="text-muted-foreground line-clamp-2">
|
||||
{relatedPost.excerpt}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -80,11 +80,10 @@ export interface Post {
|
||||
export async function getPosts(options = {}): Promise<Post[]> {
|
||||
try {
|
||||
const result = (await api.posts.browse({
|
||||
include: "authors",
|
||||
limit: "all",
|
||||
include: ["tags", "authors"],
|
||||
})) as Post[];
|
||||
console.log(result);
|
||||
|
||||
console.log("Posts data from Ghost API:", JSON.stringify(result, null, 2));
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error("Error fetching posts:", error);
|
||||
@@ -94,7 +93,10 @@ export async function getPosts(options = {}): Promise<Post[]> {
|
||||
|
||||
export async function getPost(slug: string): Promise<Post | null> {
|
||||
try {
|
||||
const result = (await api.posts.read({ slug })) as Post;
|
||||
const result = (await api.posts.read({
|
||||
slug,
|
||||
include: ["authors"],
|
||||
})) as Post;
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error("Error fetching post:", error);
|
||||
|
||||
@@ -206,6 +206,7 @@
|
||||
"postsTaggedWith": "Posts tagged with",
|
||||
"foundPosts": "{count, plural, =0 {No posts found} one {# post found} other {# posts found}}",
|
||||
"tagTitle": "Posts tagged with {tag}",
|
||||
"tagDescription": "Browse all blog posts tagged with {tag}"
|
||||
"tagDescription": "Browse all blog posts tagged with {tag}",
|
||||
"relatedPosts": "Related Posts"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,6 +205,7 @@
|
||||
"postsTaggedWith": "Articles tagués avec",
|
||||
"foundPosts": "{count, plural, =0 {Aucun article trouvé} one {# article trouvé} other {# articles trouvés}}",
|
||||
"tagTitle": "Articles tagués avec {tag}",
|
||||
"tagDescription": "Parcourir tous les articles de blog tagués avec {tag}"
|
||||
"tagDescription": "Parcourir tous les articles de blog tagués avec {tag}",
|
||||
"relatedPosts": "Articles similaires"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,6 +210,7 @@
|
||||
"postsTaggedWith": "标签为",
|
||||
"foundPosts": "{count, plural, =0 {未找到文章} other {找到 # 篇文章}}",
|
||||
"tagTitle": "标签为 {tag} 的文章",
|
||||
"tagDescription": "浏览所有标签为 {tag} 的博客文章"
|
||||
"tagDescription": "浏览所有标签为 {tag} 的博客文章",
|
||||
"relatedPosts": "相关文章"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ const nextConfig = {
|
||||
domains: [
|
||||
"static.ghost.org",
|
||||
"testing-ghost-8423be-31-220-108-27.traefik.me",
|
||||
"images.unsplash.com",
|
||||
"www.gravatar.com",
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
11
package.json
11
package.json
@@ -18,12 +18,12 @@
|
||||
"prepare": "node .husky/install.mjs"
|
||||
},
|
||||
"devDependencies": {
|
||||
"lint-staged": "^15.2.7",
|
||||
"@biomejs/biome": "1.8.3",
|
||||
"husky": "^9.1.6",
|
||||
"@commitlint/cli": "^19.3.0",
|
||||
"@commitlint/config-conventional": "^19.2.2",
|
||||
"@types/node": "^20.9.0"
|
||||
"@types/node": "^20.9.0",
|
||||
"husky": "^9.1.6",
|
||||
"lint-staged": "^15.2.7"
|
||||
},
|
||||
"packageManager": "pnpm@9.5.0",
|
||||
"engines": {
|
||||
@@ -41,5 +41,10 @@
|
||||
"resolutions": {
|
||||
"@types/react": "18.3.5",
|
||||
"@types/react-dom": "18.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"react-markdown": "^10.0.0",
|
||||
"rehype-raw": "^7.0.0",
|
||||
"remark-gfm": "^4.0.1"
|
||||
}
|
||||
}
|
||||
|
||||
157
pnpm-lock.yaml
generated
157
pnpm-lock.yaml
generated
@@ -11,6 +11,16 @@ overrides:
|
||||
importers:
|
||||
|
||||
.:
|
||||
dependencies:
|
||||
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
|
||||
@@ -1914,6 +1924,10 @@ packages:
|
||||
emoji-regex@9.2.2:
|
||||
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
|
||||
|
||||
entities@4.5.0:
|
||||
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
|
||||
engines: {node: '>=0.12'}
|
||||
|
||||
env-paths@2.2.1:
|
||||
resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==}
|
||||
engines: {node: '>=6'}
|
||||
@@ -2205,6 +2219,15 @@ packages:
|
||||
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
hast-util-from-parse5@8.0.3:
|
||||
resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==}
|
||||
|
||||
hast-util-parse-selector@4.0.0:
|
||||
resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==}
|
||||
|
||||
hast-util-raw@9.1.0:
|
||||
resolution: {integrity: sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==}
|
||||
|
||||
hast-util-to-estree@3.1.0:
|
||||
resolution: {integrity: sha512-lfX5g6hqVh9kjS/B9E2gSkvHH4SZNiQFiqWS0x9fENzEl+8W12RqdRxX6d/Cwxi30tPQs3bIO+aolQJNp1bIyw==}
|
||||
|
||||
@@ -2214,12 +2237,21 @@ packages:
|
||||
hast-util-to-jsx-runtime@2.3.2:
|
||||
resolution: {integrity: sha512-1ngXYb+V9UT5h+PxNRa1O1FYguZK/XL+gkeqvp7EdHlB9oHUG0eYRo/vY5inBdcqo3RkPMC58/H94HvkbfGdyg==}
|
||||
|
||||
hast-util-to-parse5@8.0.0:
|
||||
resolution: {integrity: sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==}
|
||||
|
||||
hast-util-to-string@3.0.1:
|
||||
resolution: {integrity: sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==}
|
||||
|
||||
hast-util-whitespace@3.0.0:
|
||||
resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==}
|
||||
|
||||
hastscript@9.0.1:
|
||||
resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==}
|
||||
|
||||
html-url-attributes@3.0.1:
|
||||
resolution: {integrity: sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==}
|
||||
|
||||
html-void-elements@3.0.0:
|
||||
resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==}
|
||||
|
||||
@@ -2796,6 +2828,9 @@ packages:
|
||||
resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
parse5@7.2.1:
|
||||
resolution: {integrity: sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==}
|
||||
|
||||
path-exists@5.0.0:
|
||||
resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
@@ -2947,6 +2982,9 @@ packages:
|
||||
property-information@6.5.0:
|
||||
resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==}
|
||||
|
||||
property-information@7.0.0:
|
||||
resolution: {integrity: sha512-7D/qOz/+Y4X/rzSB6jKxKUsQnphO046ei8qxG59mtM3RG3DHgTK81HrxrmoDVINJb8NKT5ZsRbwHvQ6B68Iyhg==}
|
||||
|
||||
proxy-from-env@1.1.0:
|
||||
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
|
||||
|
||||
@@ -2975,6 +3013,12 @@ packages:
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || ^17 || ^18 || ^19
|
||||
|
||||
react-markdown@10.0.0:
|
||||
resolution: {integrity: sha512-4mTz7Sya/YQ1jYOrkwO73VcFdkFJ8L8I9ehCxdcV0XrClHyOJGKbBk5FR4OOOG+HnyKw5u+C/Aby9TwinCteYA==}
|
||||
peerDependencies:
|
||||
'@types/react': 18.3.5
|
||||
react: '>=18'
|
||||
|
||||
react-medium-image-zoom@5.2.10:
|
||||
resolution: {integrity: sha512-JBYf4u0zsocezIDtrjwStD+8sX+c8XuLsdz+HxPbojRj0sCicua0XOQKysuPetoFyX+YgStfj+vEtZ+699O/pg==}
|
||||
peerDependencies:
|
||||
@@ -3055,12 +3099,18 @@ packages:
|
||||
regex@4.4.0:
|
||||
resolution: {integrity: sha512-uCUSuobNVeqUupowbdZub6ggI5/JZkYyJdDogddJr60L764oxC2pMZov1fQ3wM9bdyzUILDG+Sqx6NAKAz9rKQ==}
|
||||
|
||||
rehype-raw@7.0.0:
|
||||
resolution: {integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==}
|
||||
|
||||
rehype-recma@1.0.0:
|
||||
resolution: {integrity: sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==}
|
||||
|
||||
remark-gfm@4.0.0:
|
||||
resolution: {integrity: sha512-U92vJgBPkbw4Zfu/IiW2oTZLSL3Zpv+uI7My2eq8JxKgqraFdU8YUGicEJCEgSbeaG+QDFqIcwwfMTOEelPxuA==}
|
||||
|
||||
remark-gfm@4.0.1:
|
||||
resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==}
|
||||
|
||||
remark-mdx@3.0.1:
|
||||
resolution: {integrity: sha512-3Pz3yPQ5Rht2pM5R+0J2MrGoBSrzf+tJG94N+t/ilfdh8YLyyKYtidAYwTveB20BoHAcwIopOUqhcmh2F7hGYA==}
|
||||
|
||||
@@ -3402,12 +3452,18 @@ packages:
|
||||
util-deprecate@1.0.2:
|
||||
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||
|
||||
vfile-location@5.0.3:
|
||||
resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==}
|
||||
|
||||
vfile-message@4.0.2:
|
||||
resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==}
|
||||
|
||||
vfile@6.0.2:
|
||||
resolution: {integrity: sha512-zND7NlS8rJYb/sPqkb13ZvbbUoExdbi4w3SfRrMq6R3FvnLQmmfpajJNITuuYm6AZ5uao9vy4BAos3EXBPf2rg==}
|
||||
|
||||
web-namespaces@2.0.1:
|
||||
resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==}
|
||||
|
||||
which@2.0.2:
|
||||
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
|
||||
engines: {node: '>= 8'}
|
||||
@@ -5295,6 +5351,8 @@ snapshots:
|
||||
|
||||
emoji-regex@9.2.2: {}
|
||||
|
||||
entities@4.5.0: {}
|
||||
|
||||
env-paths@2.2.1: {}
|
||||
|
||||
environment@1.1.0: {}
|
||||
@@ -5691,6 +5749,37 @@ snapshots:
|
||||
dependencies:
|
||||
function-bind: 1.1.2
|
||||
|
||||
hast-util-from-parse5@8.0.3:
|
||||
dependencies:
|
||||
'@types/hast': 3.0.4
|
||||
'@types/unist': 3.0.2
|
||||
devlop: 1.1.0
|
||||
hastscript: 9.0.1
|
||||
property-information: 7.0.0
|
||||
vfile: 6.0.2
|
||||
vfile-location: 5.0.3
|
||||
web-namespaces: 2.0.1
|
||||
|
||||
hast-util-parse-selector@4.0.0:
|
||||
dependencies:
|
||||
'@types/hast': 3.0.4
|
||||
|
||||
hast-util-raw@9.1.0:
|
||||
dependencies:
|
||||
'@types/hast': 3.0.4
|
||||
'@types/unist': 3.0.2
|
||||
'@ungap/structured-clone': 1.2.0
|
||||
hast-util-from-parse5: 8.0.3
|
||||
hast-util-to-parse5: 8.0.0
|
||||
html-void-elements: 3.0.0
|
||||
mdast-util-to-hast: 13.2.0
|
||||
parse5: 7.2.1
|
||||
unist-util-position: 5.0.0
|
||||
unist-util-visit: 5.0.0
|
||||
vfile: 6.0.2
|
||||
web-namespaces: 2.0.1
|
||||
zwitch: 2.0.4
|
||||
|
||||
hast-util-to-estree@3.1.0:
|
||||
dependencies:
|
||||
'@types/estree': 1.0.5
|
||||
@@ -5746,6 +5835,16 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
hast-util-to-parse5@8.0.0:
|
||||
dependencies:
|
||||
'@types/hast': 3.0.4
|
||||
comma-separated-tokens: 2.0.3
|
||||
devlop: 1.1.0
|
||||
property-information: 6.5.0
|
||||
space-separated-tokens: 2.0.2
|
||||
web-namespaces: 2.0.1
|
||||
zwitch: 2.0.4
|
||||
|
||||
hast-util-to-string@3.0.1:
|
||||
dependencies:
|
||||
'@types/hast': 3.0.4
|
||||
@@ -5754,6 +5853,16 @@ snapshots:
|
||||
dependencies:
|
||||
'@types/hast': 3.0.4
|
||||
|
||||
hastscript@9.0.1:
|
||||
dependencies:
|
||||
'@types/hast': 3.0.4
|
||||
comma-separated-tokens: 2.0.3
|
||||
hast-util-parse-selector: 4.0.0
|
||||
property-information: 7.0.0
|
||||
space-separated-tokens: 2.0.2
|
||||
|
||||
html-url-attributes@3.0.1: {}
|
||||
|
||||
html-void-elements@3.0.0: {}
|
||||
|
||||
human-signals@5.0.0: {}
|
||||
@@ -6566,6 +6675,10 @@ snapshots:
|
||||
json-parse-even-better-errors: 2.3.1
|
||||
lines-and-columns: 1.2.4
|
||||
|
||||
parse5@7.2.1:
|
||||
dependencies:
|
||||
entities: 4.5.0
|
||||
|
||||
path-exists@5.0.0: {}
|
||||
|
||||
path-key@3.1.1: {}
|
||||
@@ -6647,6 +6760,8 @@ snapshots:
|
||||
|
||||
property-information@6.5.0: {}
|
||||
|
||||
property-information@7.0.0: {}
|
||||
|
||||
proxy-from-env@1.1.0: {}
|
||||
|
||||
queue-microtask@1.2.3: {}
|
||||
@@ -6673,6 +6788,24 @@ snapshots:
|
||||
dependencies:
|
||||
react: 18.3.1
|
||||
|
||||
react-markdown@10.0.0(@types/react@18.3.5)(react@18.3.1):
|
||||
dependencies:
|
||||
'@types/hast': 3.0.4
|
||||
'@types/mdast': 4.0.4
|
||||
'@types/react': 18.3.5
|
||||
devlop: 1.1.0
|
||||
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
|
||||
remark-parse: 11.0.0
|
||||
remark-rehype: 11.1.1
|
||||
unified: 11.0.5
|
||||
unist-util-visit: 5.0.0
|
||||
vfile: 6.0.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
react-medium-image-zoom@5.2.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||
dependencies:
|
||||
react: 18.3.1
|
||||
@@ -6784,6 +6917,12 @@ snapshots:
|
||||
|
||||
regex@4.4.0: {}
|
||||
|
||||
rehype-raw@7.0.0:
|
||||
dependencies:
|
||||
'@types/hast': 3.0.4
|
||||
hast-util-raw: 9.1.0
|
||||
vfile: 6.0.2
|
||||
|
||||
rehype-recma@1.0.0:
|
||||
dependencies:
|
||||
'@types/estree': 1.0.5
|
||||
@@ -6803,6 +6942,17 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
remark-gfm@4.0.1:
|
||||
dependencies:
|
||||
'@types/mdast': 4.0.4
|
||||
mdast-util-gfm: 3.0.0
|
||||
micromark-extension-gfm: 3.0.0
|
||||
remark-parse: 11.0.0
|
||||
remark-stringify: 11.0.0
|
||||
unified: 11.0.5
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
remark-mdx@3.0.1:
|
||||
dependencies:
|
||||
mdast-util-mdx: 3.0.0
|
||||
@@ -7224,6 +7374,11 @@ snapshots:
|
||||
|
||||
util-deprecate@1.0.2: {}
|
||||
|
||||
vfile-location@5.0.3:
|
||||
dependencies:
|
||||
'@types/unist': 3.0.2
|
||||
vfile: 6.0.2
|
||||
|
||||
vfile-message@4.0.2:
|
||||
dependencies:
|
||||
'@types/unist': 3.0.2
|
||||
@@ -7235,6 +7390,8 @@ snapshots:
|
||||
unist-util-stringify-position: 4.0.0
|
||||
vfile-message: 4.0.2
|
||||
|
||||
web-namespaces@2.0.1: {}
|
||||
|
||||
which@2.0.2:
|
||||
dependencies:
|
||||
isexe: 2.0.0
|
||||
|
||||
Reference in New Issue
Block a user