211 lines
7.2 KiB
TypeScript
211 lines
7.2 KiB
TypeScript
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, getPostContent } from "@/lib/mdx-helper";
|
||
import service from "@/lib/http/service";
|
||
import { Header, NavBack, TimeP } from "@/components/header";
|
||
import { baseTitle, baseURL, keywordsRoot } from "@/lib/metadata";
|
||
import { useTranslation } from "react-i18next";
|
||
|
||
import { useState, useEffect } from 'react';
|
||
|
||
import { DetailPageHeader } from '@/components/header'
|
||
|
||
export const runtime = "nodejs";
|
||
|
||
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 getPostContent(params.locale, params.slug);
|
||
|
||
console.log("2--------------------------generateMetadata-----------------------------", headings)
|
||
|
||
if (!frontmatter) {
|
||
return notFound();
|
||
}
|
||
|
||
const baseUrl = process.env.VERCEL_URL ? process.env.VERCEL_URL : baseURL;
|
||
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,
|
||
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 getPostContent(params.locale, params.slug);
|
||
|
||
console.log("..........................frontmatter", frontmatter)
|
||
|
||
const defaultImage = "https://gimg3.baidu.com/search/src=http%3A%2F%2Fpics3.baidu.com%2Ffeed%2F4ec2d5628535e5dd7c7cdc23847e08e2cc1b62c4.jpeg%40f_auto%3Ftoken%3D38327d5cbefb2cd45af58f8d47c0a0b5&refer=http%3A%2F%2Fwww.baidu.com&app=2021&size=f360,240&n=0&g=0n&q=75&fmt=auto?sec=1710435600&t=eafc0a27ff3295bb5b0b9065fc33a523"
|
||
|
||
|
||
// 新增状态来存储部署状态和状态文本
|
||
const [statusText, setStatusText] = useState<string>('未知');
|
||
const [progress, setProgress] = useState<string>('0%');
|
||
|
||
// 在组件加载时发起部署请求
|
||
useEffect(() => {
|
||
async function fetchDeployStatus() {
|
||
try {
|
||
const res = await fetch("/api/v1/deploy/status", {
|
||
method: "POST",
|
||
headers: { "Content-Type": "application/json" },
|
||
body: JSON.stringify({
|
||
id: frontmatter.id, // 假设 frontmatter.id 是你需要的标识符
|
||
}),
|
||
});
|
||
|
||
const json = await res.json();
|
||
|
||
if (json?.header?.code === 0) {
|
||
setStatusText(`${json.header.message || "操作成功"}`);
|
||
} else {
|
||
setStatusText(`${json.header.message || "操作失败(后端返回错误)"}`);
|
||
}
|
||
|
||
} catch (error) {
|
||
console.error('部署状态请求失败', error);
|
||
setStatusText('请求失败');
|
||
setProgress('0%');
|
||
}
|
||
}
|
||
|
||
fetchDeployStatus();
|
||
}, [frontmatter.id]); // 依赖于 frontmatter.id,每次 id 改变时重新请求
|
||
|
||
|
||
|
||
|
||
return (
|
||
<>
|
||
{/* <NavBack /> */}
|
||
<DetailPageHeader
|
||
data={{
|
||
id: frontmatter.id,
|
||
icon: frontmatter.logo_url,
|
||
name: frontmatter.p_name,
|
||
category: frontmatter.tags,
|
||
updated_at: frontmatter.date,
|
||
company: frontmatter.title,
|
||
progress: progress,
|
||
statusText: deployStatus
|
||
}}
|
||
/>
|
||
|
||
<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-2 lg:flex-row lg:space-y-0 ">
|
||
<div className="mx-auto pt-[3rem] lg:pt-[0] ">
|
||
|
||
{/* <div className="flex items-start space-x-[0.2rem] text-left text-[0.8rem] lg:text-[1rem] mb-8 text-[#808080] leading-[1.4rem] lg:leading-[4rem]">
|
||
|
||
<Link
|
||
href="/"
|
||
className=" hover:text-black focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white"
|
||
>
|
||
Blog
|
||
</Link>
|
||
<p className=" ">> </p>
|
||
<p className="">{frontmatter.title} </p>
|
||
|
||
</div>
|
||
|
||
<div className="flex items-start font-bold space-x-[2rem] text-[0.8rem] lg:text-[1.125rem] text-[#1A1A1A] leading-[1.5rem] lg:leading-[3rem] mb-[2rem]">
|
||
{
|
||
frontmatter.tags && frontmatter.tags?.length > 0 && frontmatter.tags?.map((item, index) => {
|
||
return <h4 className="border rounded-full bg-[#E5E5E5] px-[1.8rem]">{item}</h4>
|
||
})
|
||
}
|
||
</div>
|
||
|
||
<TimeP date={frontmatter.date} />
|
||
|
||
<h2 className="text-left text-[1rem] leading-[1.625rem] mb-[1rem] font-bold tracking-tight text-[#1A1A1A] sm:text-[1rem] lg:text-[1.5rem] lg:leading-[7.625rem]">
|
||
{frontmatter.title}
|
||
</h2> */}
|
||
|
||
<figure
|
||
className="w-full min-h-[146px] lg:min-h-[246px]"
|
||
>
|
||
<img src={
|
||
(
|
||
frontmatter.image_url.includes("http")
|
||
? frontmatter.image_url
|
||
: process.env.NEXT_PUBLIC_CLIENT_IMAGE_URL + frontmatter.image_url
|
||
) || defaultImage
|
||
|
||
} alt={frontmatter.title} style={{ width: '100%', marginBottom: '8px' }} />
|
||
</figure>
|
||
|
||
<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;
|
||
|