From 26cad40c68d9a026aa811d5d86ecec9f048a580e Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 2 Mar 2025 21:22:14 -0600 Subject: [PATCH] feat: re-enable blog post metadata and CodeBlock component --- .../website/app/[locale]/blog/[slug]/page.tsx | 599 +++++++++--------- apps/website/app/[locale]/blog/page.tsx | 6 +- .../app/[locale]/blog/tag/[tag]/page.tsx | 8 +- 3 files changed, 301 insertions(+), 312 deletions(-) diff --git a/apps/website/app/[locale]/blog/[slug]/page.tsx b/apps/website/app/[locale]/blog/[slug]/page.tsx index 46ee391..0705903 100644 --- a/apps/website/app/[locale]/blog/[slug]/page.tsx +++ b/apps/website/app/[locale]/blog/[slug]/page.tsx @@ -14,7 +14,7 @@ import type { BundledLanguage } from "shiki/bundle/web"; import TurndownService from "turndown"; // @ts-ignore import * as turndownPluginGfm from "turndown-plugin-gfm"; -// import { CodeBlock } from "./components/CodeBlock"; +import { CodeBlock } from "./components/CodeBlock"; import { H1, H2, H3 } from "./components/Headings"; import { TableOfContents } from "./components/TableOfContents"; import { ZoomableImage } from "./components/ZoomableImage"; @@ -22,50 +22,50 @@ type Props = { params: { locale: string; slug: string }; }; -// export async function generateMetadata( -// { params }: Props, -// parent: ResolvingMetadata, -// ): Promise { -// const { locale, slug } = await params; -// const post = await getPost(slug); +export async function generateMetadata( + { params }: Props, + parent: ResolvingMetadata, +): Promise { + const { locale, slug } = await params; + const post = await getPost(slug); -// if (!post) { -// return { -// title: "Post Not Found", -// }; -// } + if (!post) { + return { + title: "Post Not Found", + }; + } -// const ogUrl = new URL( -// `/${locale}/api/og`, -// process.env.NEXT_PUBLIC_APP_URL || "http://localhost:3000", -// ); -// ogUrl.searchParams.set("slug", slug); + const ogUrl = new URL( + `/${locale}/api/og`, + process.env.NEXT_PUBLIC_APP_URL || "http://localhost:3000", + ); + ogUrl.searchParams.set("slug", slug); -// return { -// title: post.title, -// description: post.custom_excerpt || post.excerpt, -// openGraph: { -// title: post.title, -// description: post.custom_excerpt || post.excerpt, -// type: "article", -// url: `${process.env.NEXT_PUBLIC_APP_URL}/blog/${post.slug}`, -// images: [ -// { -// url: ogUrl.toString(), -// width: 1200, -// height: 630, -// alt: post.title, -// }, -// ], -// }, -// twitter: { -// card: "summary_large_image", -// title: post.title, -// description: post.custom_excerpt || post.excerpt, -// images: [ogUrl.toString()], -// }, -// }; -// } + return { + title: post.title, + description: post.custom_excerpt || post.excerpt, + openGraph: { + title: post.title, + description: post.custom_excerpt || post.excerpt, + type: "article", + url: `${process.env.NEXT_PUBLIC_APP_URL}/blog/${post.slug}`, + images: [ + { + url: ogUrl.toString(), + width: 1200, + height: 630, + alt: post.title, + }, + ], + }, + twitter: { + card: "summary_large_image", + title: post.title, + description: post.custom_excerpt || post.excerpt, + images: [ogUrl.toString()], + }, + }; +} export async function generateStaticParams() { const posts = await getPosts(); @@ -80,291 +80,282 @@ export async function generateStaticParams() { } export default async function BlogPostPage({ params }: Props) { - try { - const { locale, slug } = await params; - // setRequestLocale(locale); - const t = await getTranslations({ locale, namespace: "blog" }); - const post = await getPost(slug); - const allPosts = await getPosts(); + const { slug } = await params; + // setRequestLocale(locale); + const t = await getTranslations("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 + // 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(); - } + if (!post) { + notFound(); + } - // Convertir HTML a Markdown - const turndownService = new TurndownService({ - headingStyle: "atx", - codeBlockStyle: "fenced", - }); - const gfm = turndownPluginGfm.gfm; - const tables = turndownPluginGfm.tables; - const strikethrough = turndownPluginGfm.strikethrough; - turndownService.use([tables, strikethrough, gfm, remarkToc]); + // Convertir HTML a Markdown + const turndownService = new TurndownService({ + headingStyle: "atx", + codeBlockStyle: "fenced", + }); + const gfm = turndownPluginGfm.gfm; + const tables = turndownPluginGfm.tables; + const strikethrough = turndownPluginGfm.strikethrough; + turndownService.use([tables, strikethrough, gfm, remarkToc]); - const markdown = turndownService.turndown(post.html); + const markdown = turndownService.turndown(post.html); - const formattedDate = new Date(post.published_at).toLocaleDateString( - locale, - { - year: "numeric", - month: "long", - day: "numeric", - }, - ); + const formattedDate = new Date(post.published_at).toLocaleDateString("en", { + year: "numeric", + month: "long", + day: "numeric", + }); - const components: Partial = { - h1: H1, - h2: H2, - h3: H3, - p: ({ node, children, ...props }) => ( -

= { + h1: H1, + h2: H2, + h3: H3, + p: ({ node, children, ...props }) => ( +

+ {children} +

+ ), + a: ({ node, href, ...props }) => ( + + ), + ul: ({ node, ...props }) => ( +
    + ), + ol: ({ node, ...props }) => ( +
      + ), + li: ({ node, ...props }) => ( +
    1. + ), + blockquote: ({ node, ...props }) => ( +
      + ), + table: ({ node, ...props }) => ( +
      + + + ), + thead: ({ node, ...props }) => ( + + ), + tbody: ({ node, ...props }) => ( + + ), + tr: ({ node, ...props }) => ( + + ), + th: ({ node, ...props }) => ( +
      + ), + td: ({ node, ...props }) => ( + + ), + img: ({ node, src, alt }) => ( + + ), + code: ({ className, children }) => { + const match = /language-(\w+)/.exec(className || ""); + return ( + + ); + }, + }; + + return ( +
      + + - {children} -

      - ), - a: ({ node, href, ...props }) => ( - - ), - ul: ({ node, ...props }) => ( -
        - ), - ol: ({ node, ...props }) => ( -
          - ), - li: ({ node, ...props }) => ( -
        1. - ), - blockquote: ({ node, ...props }) => ( -
          - ), - table: ({ node, ...props }) => ( -
          - - - ), - thead: ({ node, ...props }) => ( - - ), - tbody: ({ node, ...props }) => ( - - ), - tr: ({ node, ...props }) => ( - - ), - th: ({ node, ...props }) => ( -
          - ), - td: ({ node, ...props }) => ( - - ), - img: ({ node, src, alt }) => ( - - ), - // code: ({ className, children }) => { - // const match = /language-(\w+)/.exec(className || ""); - // return ( - // - // ); - // }, - }; + + + {t("backToBlog")} + - return ( -
          - - - - - {t("backToBlog")} - - -
          -
          -
          -

          - {post.title} -

          -
          - {post.primary_author?.profile_image && ( -
          - {post.primary_author.twitter ? ( - - {post.primary_author.name} - - ) : ( +
          +
          +
          +

          + {post.title} +

          +
          + {post.primary_author?.profile_image && ( +
          + {post.primary_author.twitter ? ( + {post.primary_author.name} - )} -
          - )} -
          -

          - {post.primary_author?.twitter ? ( - - {post.primary_author.name || "Unknown Author"} - - ) : ( - post.primary_author?.name || "Unknown Author" - )} -

          -

          - {formattedDate} • {post.reading_time} min read -

          -
          -
          - {post.feature_image && ( -
          - + + ) : ( + {post.primary_author.name} + )}
          )} -
          - -
          - - {markdown} - -
          - - {post.tags && post.tags.length > 0 && ( -
          -

          {t("tags")}

          -
          - {post.tags.map((tag) => ( - +

          + {post.primary_author?.twitter ? ( + - {tag.name} - - ))} -

          + {post.primary_author.name || "Unknown Author"} + + ) : ( + post.primary_author?.name || "Unknown Author" + )} +

          +

          + {formattedDate} • {post.reading_time} min read +

          +
          +
          + {post.feature_image && ( +
          +
          )} +
          + +
          + + {markdown} +
          -
          -
          - + {post.tags && post.tags.length > 0 && ( +
          +

          {t("tags")}

          +
          + {post.tags.map((tag) => ( + + {tag.name} + + ))} +
          -
          + )}
          - {relatedPosts.length > 0 && ( -
          -

          {t("relatedPosts")}

          -
          - {relatedPosts.map((relatedPost) => { - const relatedPostDate = new Date( - relatedPost.published_at, - ).toLocaleDateString(locale, { - year: "numeric", - month: "long", - day: "numeric", - }); - - return ( - -
          - {relatedPost.feature_image && ( -
          - {relatedPost.title} -
          - )} -
          -

          - {relatedPost.title} -

          -

          - {relatedPostDate} • {relatedPost.reading_time} min - read -

          -

          - {relatedPost.excerpt} -

          -
          -
          - - ); - })} -
          +
          +
          +
          - )} -
          - ); - } catch (error) { - console.error("Error in BlogPostPage:", error); - return
          Error loading blog post
          ; - } + + + + {relatedPosts.length > 0 && ( +
          +

          {t("relatedPosts")}

          +
          + {relatedPosts.map((relatedPost) => { + const relatedPostDate = new Date( + relatedPost.published_at, + ).toLocaleDateString("en", { + year: "numeric", + month: "long", + day: "numeric", + }); + + return ( + +
          + {relatedPost.feature_image && ( +
          + {relatedPost.title} +
          + )} +
          +

          + {relatedPost.title} +

          +

          + {relatedPostDate} • {relatedPost.reading_time} min read +

          +

          + {relatedPost.excerpt} +

          +
          +
          + + ); + })} +
          +
          + )} + + ); } diff --git a/apps/website/app/[locale]/blog/page.tsx b/apps/website/app/[locale]/blog/page.tsx index 091a27b..cffd450 100644 --- a/apps/website/app/[locale]/blog/page.tsx +++ b/apps/website/app/[locale]/blog/page.tsx @@ -2,11 +2,10 @@ import { getPosts, getTags } from "@/lib/ghost"; import type { Post } from "@/lib/ghost"; import { RssIcon } from "lucide-react"; import type { Metadata } from "next"; -import { getTranslations, setRequestLocale } from "next-intl/server"; +import { getTranslations } from "next-intl/server"; import Link from "next/link"; import { BlogPostCard } from "./components/BlogPostCard"; import { SearchAndFilter } from "./components/SearchAndFilter"; - interface Tag { id: string; name: string; @@ -27,8 +26,7 @@ export default async function BlogPage({ }) { const { locale } = await params; const searchParams2 = await searchParams; - setRequestLocale(locale); - const t = await getTranslations({ locale, namespace: "blog" }); + const t = await getTranslations("blog"); const posts = await getPosts(); const tags = (await getTags()) as Tag[]; const search = diff --git a/apps/website/app/[locale]/blog/tag/[tag]/page.tsx b/apps/website/app/[locale]/blog/tag/[tag]/page.tsx index 4d66662..c8806e5 100644 --- a/apps/website/app/[locale]/blog/tag/[tag]/page.tsx +++ b/apps/website/app/[locale]/blog/tag/[tag]/page.tsx @@ -11,8 +11,8 @@ type Props = { }; export async function generateMetadata({ params }: Props): Promise { - const { tag, locale } = params; - const t = await getTranslations({ locale, namespace: "blog" }); + const { tag } = await params; + const t = await getTranslations("blog"); return { title: `${t("tagTitle", { tag })}`, @@ -29,8 +29,8 @@ export async function generateStaticParams() { } export default async function TagPage({ params }: Props) { - const { locale, tag } = params; - const t = await getTranslations({ locale, namespace: "blog" }); + const { tag } = await params; + const t = await getTranslations("blog"); const posts = await getPostsByTag(tag); if (!posts || posts.length === 0) {