diff --git a/next.config.mjs b/next.config.mjs
index ac46786..d730e0c 100644
--- a/next.config.mjs
+++ b/next.config.mjs
@@ -1,33 +1,34 @@
-import createMDX from '@next/mdx'
-import bundleAnalyzer from '@next/bundle-analyzer'
+import createMDX from "@next/mdx";
+import bundleAnalyzer from "@next/bundle-analyzer";
/** @type {import('next').NextConfig} */
const nextConfig = {
- output: 'export',
+ output: "export",
reactStrictMode: true,
compress: true,
poweredByHeader: false,
optimizeFonts: true,
swcMinify: true,
images: {
- unoptimized: true
+ unoptimized: true,
},
- pageExtensions: ['js', 'jsx', 'md', 'mdx', 'ts', 'tsx'],
+ pageExtensions: ["js", "jsx", "md", "mdx", "ts", "tsx"],
webpack: (config, { isServer }) => {
if (!isServer) {
config.externals = {
// 添加其他需要从 CDN 加载的依赖
- }
+ };
}
- return config
+ return config;
},
+ // experimental: { turbo: {} },
};
-const withMDX = createMDX({})
+const withMDX = createMDX({});
// 修改 bundle-analyzer 配置
const withBundleAnalyzer = bundleAnalyzer({
- enabled: process.env.ANALYZE === 'true',
-})
+ enabled: process.env.ANALYZE === "true",
+});
-export default withBundleAnalyzer(withMDX(nextConfig));
\ No newline at end of file
+export default withBundleAnalyzer(withMDX(nextConfig));
diff --git a/package.json b/package.json
index 8136e06..23b1929 100644
--- a/package.json
+++ b/package.json
@@ -1,5 +1,5 @@
{
- "name": "my-app",
+ "name": "next-blog",
"version": "0.1.0",
"private": true,
"scripts": {
@@ -8,7 +8,6 @@
"analyze": "pnpm clean && ANALYZE=true next build",
"start": "next start",
"lint": "next lint",
- "export": "next export",
"clean": "rm -rf .next"
},
"dependencies": {
diff --git a/public/svg/check-dark.svg b/public/svg/check-dark.svg
index d4c5fa8..5b00714 100644
--- a/public/svg/check-dark.svg
+++ b/public/svg/check-dark.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/svg/copy-dark.svg b/public/svg/copy-dark.svg
index f0c4615..ee08e0f 100644
--- a/public/svg/copy-dark.svg
+++ b/public/svg/copy-dark.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/src/app/blog/BlogClientComponent.tsx b/src/app/blog/BlogClientComponent.tsx
index bca9bcb..f7608f3 100644
--- a/src/app/blog/BlogClientComponent.tsx
+++ b/src/app/blog/BlogClientComponent.tsx
@@ -24,8 +24,8 @@ import {
SelectTrigger,
SelectValue,
} from "@/components/ui";
-import { ChevronDown, ChevronUp } from "lucide-react";
-import { AlertCircle } from "lucide-react";
+import { ChevronDown, ChevronUp, AlertCircle } from "lucide-react";
+import { motion, AnimatePresence } from "framer-motion";
const POSTS_PER_PAGE = 6;
const INITIAL_TAG_COUNT = 10;
@@ -33,6 +33,12 @@ const INITIAL_TAG_COUNT = 10;
// 添加新的排序选项类型
type SortOption = "date" | "title";
+const cardVariants = {
+ hidden: { opacity: 0, y: -20 },
+ visible: { opacity: 1, y: 0 },
+ exit: { opacity: 0, y: 20 },
+};
+
export default function BlogList() {
const router = useRouter();
const searchParams = useSearchParams();
@@ -218,35 +224,52 @@ export default function BlogList() {
))
) : currentPosts.length > 0 ? (
- currentPosts.map((post) => (
-
-
-
-
- {post.title}
-
-
-
- {post.date} | {post.author}
-
-
-
- {post.excerpt}
-
-
- {post.tags.map((tag) => (
- handleTagClick(tag)}
- >
- {tag}
-
- ))}
-
-
- ))
+
+ {currentPosts.map((post, index) => (
+
+
+
+
+
+ {post.title}
+
+
+
+ {post.date} | {post.author}
+
+
+
+
+ {post.excerpt}
+
+
+
+ {post.tags.map((tag) => (
+ handleTagClick(tag)}
+ >
+ {tag}
+
+ ))}
+
+
+
+ ))}
+
) : (
@@ -266,21 +289,29 @@ export default function BlogList() {
)}
{filteredPostsMemo.length > 0 && (
-
- {Array.from(
- { length: Math.ceil(filteredPostsMemo.length / POSTS_PER_PAGE) },
- (_, i) => (
-
- )
- )}
-
+
+
+ {Array.from(
+ { length: Math.ceil(filteredPostsMemo.length / POSTS_PER_PAGE) },
+ (_, i) => (
+
+ )
+ )}
+
+
)}
);
diff --git a/src/app/blog/[id]/AnimatedBlogPost.tsx b/src/app/blog/[id]/AnimatedBlogPost.tsx
new file mode 100644
index 0000000..be4b406
--- /dev/null
+++ b/src/app/blog/[id]/AnimatedBlogPost.tsx
@@ -0,0 +1,60 @@
+'use client';
+
+import { motion } from 'framer-motion';
+import BlogHeader from "./BlogHeader";
+import BlogContent from "./BlogContent";
+import BlogFooter from "./BlogFooter";
+import RelatedPosts from "./RelatedPosts";
+import ShareButtons from "./ShareButtons";
+import TableOfContents from "./TableOfContents";
+import Comments from "@/components/Comments";
+import { mdxComponents } from "./MdxComponents";
+import type { BlogPost, Heading } from "./types";
+
+interface AnimatedBlogPostProps {
+ post: BlogPost;
+ headings: Heading[];
+ readingTime: number;
+ relatedPosts: BlogPost[];
+}
+
+export default function AnimatedBlogPost({ post, headings, readingTime, relatedPosts }: AnimatedBlogPostProps) {
+ return (
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/app/blog/[id]/MdxComponents.tsx b/src/app/blog/[id]/MdxComponents.tsx
index 4b9978b..e480024 100644
--- a/src/app/blog/[id]/MdxComponents.tsx
+++ b/src/app/blog/[id]/MdxComponents.tsx
@@ -68,6 +68,7 @@ export const mdxComponents: MDXComponents = {
customStyle={{
backgroundColor: "var(--code-bg)",
color: "var(--code-text)",
+ paddingRight: "7rem",
}}
{...props}
/>
diff --git a/src/app/blog/[id]/page.tsx b/src/app/blog/[id]/page.tsx
index a585f10..4180c32 100644
--- a/src/app/blog/[id]/page.tsx
+++ b/src/app/blog/[id]/page.tsx
@@ -1,17 +1,13 @@
-import { serialize } from "next-mdx-remote/serialize";
import { notFound } from "next/navigation";
import { blogPosts } from "@/data/blogPosts";
-import Comments from "@/components/Comments";
import ReadingProgress from "@/components/ReadingProgress";
import { extractHeadings, estimateReadingTime } from "@/utils/blogHelpers";
-import BlogHeader from "./BlogHeader";
-import BlogContent from "./BlogContent";
-import BlogFooter from "./BlogFooter";
-import RelatedPosts from "./RelatedPosts";
-import ShareButtons from "./ShareButtons";
-import TableOfContents from "./TableOfContents";
-import { mdxComponents } from "./MdxComponents";
import type { BlogPost, Heading } from "./types";
+import dynamic from "next/dynamic";
+
+const AnimatedBlogPost = dynamic(() => import("./AnimatedBlogPost"), {
+ ssr: false,
+});
interface BlogPostParams {
params: { id: string };
@@ -42,29 +38,14 @@ export default async function BlogPost({ params }: BlogPostParams) {
.slice(0, 3);
return (
-
+
+ >
);
}
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index 21c8a55..82a93fd 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -7,6 +7,7 @@ import Footer from "@/components/Footer";
import { cn } from "@/lib/utils";
import { ThemeProvider } from "next-themes";
+import AnimatedLayout from "@/components/AnimatedLayout";
const inter = Inter({ subsets: ["latin"], variable: "--font-sans" });
@@ -31,7 +32,11 @@ export default function RootLayout({
>
- {children}
+
+
+ {children}
+
+