hts/apps/blogai/app/[locale]/qa/[slug]/page.tsx

143 lines
4.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Container } from "@/components/landing/container";
import { FadeIn } from "@/components/landing/fade-in";
import { MdxContent } from "@/components/landing/mdx-content";
// import { PageLinks } from "@/components/landing/page-links";
import { Avatar, AvatarImage } from "@/components/ui/avatar";
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";
import { authors } from "@/content/blog/authors";
import type { GetServerSideProps, Metadata } from "next";
import Link from "next/link";
import { notFound } from "next/navigation";
import { BLOG_PATH, getContentData, getFilePaths, getPost, getQAContent } from "@/lib/mdx-helper";
import { getService } from "@/lib/http/service";
import { Header, NavBack, TimeP } from "@/components/header";
import { baseTitle, baseURL, keywordsRoot } from "@/lib/metadata";
import { getBaseUrl } from "@/lib/http/get-base-url"; // ✅ 不是 export 它,而是 import 用
export const runtime = "nodejs";
// // 推荐用法async 获取
// export async function getBaseUrl() {
// let ip = await getRuntimeEnv("SUPABASE_URL");
// if (!ip) throw new Error("SUPABASE_URL 获取失败,无法构建 baseUrl");
// // 判断协议
// let protocol = "http";
// if (
// typeof window !== "undefined" &&
// window.location &&
// window.location.protocol === "https:"
// ) {
// protocol = "https";
// // ✅ 只在 HTTPS 客户端场景下用 hostname 替换 IP
// ip = window.location.hostname;
// }
// // 拼接
// return `${protocol}://${ip}`;
// }
type Props = {
params: { locale: string, slug: string; title: string; description: string; authorName: string };
searchParams: { [key: string]: string | string[] | undefined };
};
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { serialized, frontmatter, headings } = await getQAContent(params.locale, params.slug);
console.log("1------------------------generateMetadata----------------------------", headings)
if (!frontmatter) {
return notFound();
}
//const baseUrl = process.env.VERCEL_URL ? process.env.VERCEL_URL : baseURL;
const baseUrl = await getBaseUrl();
const ogUrl = new URL("/og/blog", baseUrl);
const author = authors[frontmatter.author];
ogUrl.searchParams.set("title", frontmatter.title ?? "");
return {
title: `${frontmatter.title}`,
description: frontmatter.description,
category: `${headings.text}`,
keywords: keywordsRoot(headings.text || ""),
openGraph: {
title: `${frontmatter.title} | ${baseTitle}`,
description: frontmatter.description,
type: "article",
images: [
{
url: ogUrl.toString(),
width: 1200,
height: 630,
alt: frontmatter.title,
},
],
},
twitter: {
card: "summary_large_image",
title: `${frontmatter.title} | ${baseTitle}`,
description: frontmatter.description,
images: [
{
url: ogUrl.toString(),
width: 1200,
height: 630,
alt: frontmatter.title,
},
],
},
icons: {
shortcut: "/favicon.png",
},
};
}
const BlogArticleWrapper = async ({ params }: { params: { slug: string, locale: string, } }) => {
const { serialized, frontmatter, headings } = await getQAContent(params.locale, params.slug);
console.log("frontmatter", frontmatter)
return (
<>
<NavBack />
<div className='mb-40 md:mb-60 w-11/12 lg:w-2/3 xl:w-3/5 mx-auto'>
<Container className="scroll-smooth">
<div className="relative mt-0 flex flex-col items-start space-y-8 lg:mt-32 lg:flex-row lg:space-y-0 ">
<div className="mx-auto ">
<div className="flex items-start justify-between space-x-[2rem] text-[1.125rem] text-[#1A1A1A] leading-[3rem] mt-[2rem]">
{/* <p className=" text-left text-[1rem] text-[#666666]">{frontmatter.date}</p>
<h6>JellyAI</h6> */}
<TimeP date={frontmatter.date} />
</div>
<h2 className="text-left text-[1.25rem] leading-[7.625rem] font-bold tracking-tight text-[#1A1A1A] sm:text-[1.5rem]">
{frontmatter.title}
</h2>
<div className="prose prose-neutral dark:prose-invert prose-pre:border prose-pre:border-border prose-pre:rounded-lg prose-img:rounded-lg prose-img:border prose-img:border-border mx-auto w-full max-w-max">
<MdxContent source={serialized} />
</div>
</div>
<div className="pt-16"></div>
</div>
</Container>
</div>
</>
);
};
export default BlogArticleWrapper;