Skip to content

Commit

Permalink
Merge pull request #1 from zhuba-Ahhh/dev
Browse files Browse the repository at this point in the history
refactor: ♻️ 拆分组件
  • Loading branch information
zhuba-Ahhh authored Aug 24, 2024
2 parents a2467c6 + f6abd3c commit 4d2fb49
Show file tree
Hide file tree
Showing 16 changed files with 434 additions and 326 deletions.
1 change: 1 addition & 0 deletions public/svg/check-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion public/svg/check.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions public/svg/copy-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion public/svg/copy.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 32 additions & 0 deletions src/app/blog/[id]/BlogContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { MDXRemote } from "next-mdx-remote/rsc";
import { MDXComponents } from "./types";

import remarkGfm from "remark-gfm";
import rehypeInlineCode from "@/lib/rehypeInlineCode";
import rehypeSlug from "rehype-slug";
import rehypeAutolinkHeadings from "rehype-autolink-headings";

interface BlogContentProps {
content: string;
components: MDXComponents;
}

export default function BlogContent({ content, components }: BlogContentProps) {
return (
<MDXRemote
source={content}
components={components}
options={{
mdxOptions: {
remarkPlugins: [remarkGfm],
rehypePlugins: [
rehypeSlug,
[rehypeAutolinkHeadings, { behavior: "wrap" }],
rehypeInlineCode,
],
},
parseFrontmatter: true,
}}
/>
);
}
29 changes: 29 additions & 0 deletions src/app/blog/[id]/BlogFooter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import Link from "next/link";
import { Badge, Button } from "@/components/ui";
import { BlogPost } from "./types";

interface BlogFooterProps {
post: BlogPost;
}

export default function BlogFooter({ post }: BlogFooterProps) {
return (
<>
<div className="mb-6 flex flex-wrap gap-2">
{post.tags.map((tag) => (
<Link key={tag} href={`/blog?tag=${encodeURIComponent(tag)}`}>
<Badge
variant="secondary"
className="cursor-pointer hover:bg-secondary-hover"
>
{tag}
</Badge>
</Link>
))}
</div>
<Button asChild variant="outline">
<Link href="/blog">&larr; 返回博客列表</Link>
</Button>
</>
);
}
29 changes: 29 additions & 0 deletions src/app/blog/[id]/BlogHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import Image from "next/image";
import { BlogPost } from "./types";

interface BlogHeaderProps {
post: BlogPost;
readingTime: number;
}

export default function BlogHeader({ post, readingTime }: BlogHeaderProps) {
return (
<>
<h1 className="text-4xl font-bold mb-4">{post.title}</h1>
<div className="mb-4 text-muted-foreground">
<span>{post.date}</span> | <span>{post.author}</span> |
<span>预计阅读时间: {readingTime} 分钟</span>
</div>
{post.coverImage && (
<Image
src={post.coverImage}
alt={post.title}
width={800}
height={400}
layout="responsive"
className="rounded-lg mb-6"
/>
)}
</>
);
}
79 changes: 79 additions & 0 deletions src/app/blog/[id]/MdxComponents.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import { oneLight } from "react-syntax-highlighter/dist/esm/styles/prism";
import dynamic from "next/dynamic";
import { MDXComponents } from "./types";

const CopyButton = dynamic(() => import("@/components/CopyButton"), {
ssr: false,
});

export const mdxComponents: MDXComponents = {
h1: (props: any) => (
<h1
className="text-3xl font-bold mt-8 mb-4 text-gray-900 dark:text-white scroll-mt-20"
{...props}
/>
),
h2: (props: any) => (
<h2
className="text-2xl font-semibold mt-6 mb-3 text-gray-800 dark:text-gray-200 scroll-mt-20"
{...props}
/>
),
h3: (props: any) => (
<h3
className="text-xl font-medium mt-4 mb-2 text-gray-700 dark:text-gray-300 scroll-mt-20"
{...props}
/>
),
p: (props: any) => (
<p className="mb-4 text-gray-600 dark:text-gray-400" {...props} />
),
a: (props: any) => (
<a
className="text-blue-500 hover:underline dark:text-blue-400"
{...props}
/>
),
ol: (props: any) => (
<ol
className="list-decimal list-inside mb-4 text-gray-600 dark:text-gray-400"
{...props}
/>
),
li: (props: any) => (
<li className="mb-2 text-gray-600 dark:text-gray-400" {...props} />
),
code: ({ className, ...props }: any) => {
const match = /language-(\w+)/.exec(className || "");
const language = match ? match[1] : "text";
const isInline = className === "inline-code";
if (isInline) {
return (
<code
className="bg-gray-100 dark:bg-gray-800 rounded px-1 py-0.5 font-mono text-sm"
{...props}
/>
);
}
return (
<div className="relative group">
<SyntaxHighlighter
language={language}
style={oneLight}
className="bg-code-light dark:bg-code-dark rounded-lg p-4 my-4 overflow-auto"
codeTagProps={{
className: "text-code-light dark:text-code-dark",
}}
customStyle={{
backgroundColor: "var(--code-bg)",
color: "var(--code-text)",
}}
{...props}
/>
<CopyButton text={props.children} language={language} />
</div>
);
},
pre: (props: any) => <div {...props} />,
};
31 changes: 31 additions & 0 deletions src/app/blog/[id]/RelatedPosts.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import Link from "next/link";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui";
import { BlogPost } from "./types";

function RelatedPosts({ posts }: { posts: BlogPost[] }) {
if (posts.length === 0) return null;

return (
<Card className="mt-12">
<CardHeader>
<CardTitle>相关文章</CardTitle>
</CardHeader>
<CardContent>
<ul className="space-y-2">
{posts.map((relatedPost) => (
<li key={relatedPost.id}>
<Link
href={`/blog/${relatedPost.id}`}
className="text-primary hover:underline"
>
{relatedPost.title}
</Link>
</li>
))}
</ul>
</CardContent>
</Card>
);
}

export default RelatedPosts;
37 changes: 37 additions & 0 deletions src/app/blog/[id]/ShareButtons.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { FaTwitter, FaFacebook, FaLinkedin } from "react-icons/fa";

interface ShareButtonsProps {
url: string;
title: string;
}

export default function ShareButtons({ url, title }: ShareButtonsProps) {
return (
<div className="flex space-x-4 mt-6">
<a
href={`https://twitter.com/intent/tweet?url=${url}&text=${title}`}
target="_blank"
rel="noopener noreferrer"
className="text-blue-400 hover:text-blue-500"
>
<FaTwitter size={24} />
</a>
<a
href={`https://www.facebook.com/sharer/sharer.php?u=${url}`}
target="_blank"
rel="noopener noreferrer"
className="text-blue-600 hover:text-blue-700"
>
<FaFacebook size={24} />
</a>
<a
href={`https://www.linkedin.com/shareArticle?mini=true&url=${url}&title=${title}`}
target="_blank"
rel="noopener noreferrer"
className="text-blue-700 hover:text-blue-800"
>
<FaLinkedin size={24} />
</a>
</div>
);
}
37 changes: 37 additions & 0 deletions src/app/blog/[id]/TableOfContents.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React from "react";
import { Heading } from "./types";

interface TableOfContentsProps {
headings: Heading[];
}

const TableOfContents = React.memo(function TableOfContents({
headings,
}: TableOfContentsProps) {
return (
<div className="bg-gray-100 dark:bg-gray-700 p-4 rounded-lg sticky top-20 w-[240px] mr-2">
<h2 className="text-lg font-bold mb-3 text-gray-900 dark:text-white">
目录
</h2>
<nav>
<ul className="space-y-1">
{headings.map((heading, index) => (
<li key={index} className={`${heading.level === 3 ? "ml-2" : ""}`}>
<a
href={`#${heading.slug}`}
className="text-primary dark:text-primary-light hover:underline text-sm block truncate"
title={heading.text}
>
{heading.text.length > 20
? heading.text.slice(0, 20) + "..."
: heading.text}
</a>
</li>
))}
</ul>
</nav>
</div>
);
});

export default TableOfContents;
Loading

0 comments on commit 4d2fb49

Please sign in to comment.