Files
AboutMe/components/project-intro-dialog.tsx
T
2026-08-19 18:05:20 +08:00

84 lines
3.0 KiB
TypeScript

"use client";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import type { Components } from "react-markdown";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogTitle,
DialogTrigger
} from "@/components/ui/dialog";
type ProjectIntroDialogProps = {
title: string;
intro?: string;
};
const markdownComponents: Components = {
a: ({ href, children }) => (
<a href={href} target="_blank" rel="noopener noreferrer">
{children}
</a>
),
img: ({ src, alt }) => (
<img
src={typeof src === "string" ? src : undefined}
alt={alt ?? ""}
className="my-3 h-auto w-full rounded-lg border border-border"
/>
),
table: ({ children }) => (
<div className="mb-3 overflow-x-auto">
<table className="w-full border-collapse text-xs">{children}</table>
</div>
),
th: ({ children }) => (
<th className="border border-border bg-muted/50 px-2 py-1.5 text-left font-medium text-foreground">
{children}
</th>
),
td: ({ children }) => (
<td className="border border-border px-2 py-1.5">{children}</td>
)
};
/** 可选的项目介绍:shadcn Button 打开 Dialog,正文按 Markdown 渲染 */
export const ProjectIntroDialog = ({
title,
intro = ""
}: ProjectIntroDialogProps) => {
const body = intro.trim() || "暂无介绍";
return (
<Dialog>
<DialogTrigger
render={
<Button
variant="outline"
className="h-auto rounded-full border-border px-5 py-2.5 text-xs font-medium uppercase tracking-[0.15em]"
/>
}
>
Intro
</DialogTrigger>
<DialogContent className="max-w-2xl p-6">
<DialogTitle>{title}</DialogTitle>
<DialogDescription className="sr-only">{title} 项目介绍</DialogDescription>
<div
className="mt-3 max-h-[70vh] overflow-y-auto [scrollbar-width:none] [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden text-sm leading-relaxed text-muted-foreground [&_a]:text-foreground [&_a]:underline [&_a]:underline-offset-4 [&_blockquote]:border-l-2 [&_blockquote]:border-border [&_blockquote]:pl-3 [&_code]:rounded [&_code]:bg-muted [&_code]:px-1 [&_code]:py-0.5 [&_code]:font-mono [&_code]:text-xs [&_h1]:mb-2 [&_h1]:text-base [&_h1]:font-medium [&_h1]:text-foreground [&_h2]:mt-5 [&_h2]:mb-2 [&_h2]:text-sm [&_h2]:font-medium [&_h2]:text-foreground [&_h3]:mt-4 [&_h3]:mb-2 [&_h3]:text-sm [&_h3]:font-medium [&_h3]:text-foreground [&_ol]:mb-3 [&_ol]:list-decimal [&_ol]:space-y-1 [&_ol]:pl-5 [&_p]:mb-3 [&_p]:last:mb-0 [&_pre]:mb-3 [&_pre]:overflow-x-auto [&_pre]:rounded-lg [&_pre]:bg-muted [&_pre]:p-3 [&_strong]:font-medium [&_strong]:text-foreground [&_ul]:mb-3 [&_ul]:list-disc [&_ul]:space-y-1 [&_ul]:pl-5"
>
<ReactMarkdown
remarkPlugins={[remarkGfm]}
components={markdownComponents}
>
{body}
</ReactMarkdown>
</div>
</DialogContent>
</Dialog>
);
};