Skip to content

Commit

Permalink
Merge pull request #2 from zhuba-Ahhh/dev
Browse files Browse the repository at this point in the history
feat: ✨ framer-motion
  • Loading branch information
zhuba-Ahhh authored Aug 24, 2024
2 parents 4d2fb49 + 7d8ba20 commit 93fb7c6
Show file tree
Hide file tree
Showing 11 changed files with 255 additions and 116 deletions.
23 changes: 12 additions & 11 deletions next.config.mjs
Original file line number Diff line number Diff line change
@@ -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));
export default withBundleAnalyzer(withMDX(nextConfig));
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "my-app",
"name": "next-blog",
"version": "0.1.0",
"private": true,
"scripts": {
Expand All @@ -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": {
Expand Down
2 changes: 1 addition & 1 deletion 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/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.
123 changes: 77 additions & 46 deletions src/app/blog/BlogClientComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,21 @@ 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;

// 添加新的排序选项类型
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();
Expand Down Expand Up @@ -218,35 +224,52 @@ export default function BlogList() {
</Card>
))
) : currentPosts.length > 0 ? (
currentPosts.map((post) => (
<Card key={post.id}>
<CardHeader>
<CardTitle>
<Link href={`/blog/${post.id}`} className="hover:underline">
{post.title}
</Link>
</CardTitle>
<CardDescription>
{post.date} | {post.author}
</CardDescription>
</CardHeader>
<CardContent>
<p>{post.excerpt}</p>
</CardContent>
<CardFooter className="flex flex-wrap gap-2">
{post.tags.map((tag) => (
<Badge
key={tag}
variant="secondary"
className="text-xs px-2 py-1 h-6 cursor-pointer"
onClick={() => handleTagClick(tag)}
>
{tag}
</Badge>
))}
</CardFooter>
</Card>
))
<AnimatePresence mode="wait">
{currentPosts.map((post, index) => (
<motion.div
key={post.id}
variants={cardVariants}
initial="hidden"
animate="visible"
exit="exit"
transition={{ duration: 0.3, delay: index * 0.1 }}
layout
>
<Card>
<CardHeader>
<CardTitle>
<Link
href={`/blog/${post.id}`}
className="hover:underline"
>
{post.title}
</Link>
</CardTitle>
<CardDescription>
{post.date} | {post.author}
</CardDescription>
</CardHeader>
<CardContent>
<p className="line-clamp-1 overflow-hidden">
{post.excerpt}
</p>
</CardContent>
<CardFooter className="flex flex-wrap gap-2">
{post.tags.map((tag) => (
<Badge
key={tag}
variant="secondary"
className="text-xs px-2 py-1 h-6 cursor-pointer"
onClick={() => handleTagClick(tag)}
>
{tag}
</Badge>
))}
</CardFooter>
</Card>
</motion.div>
))}
</AnimatePresence>
) : (
<div className="col-span-full">
<Alert variant="default">
Expand All @@ -266,21 +289,29 @@ export default function BlogList() {
)}
</div>
{filteredPostsMemo.length > 0 && (
<div className="mt-8 flex justify-center">
{Array.from(
{ length: Math.ceil(filteredPostsMemo.length / POSTS_PER_PAGE) },
(_, i) => (
<Button
key={i}
onClick={() => paginate(i + 1)}
variant={currentPage === i + 1 ? "default" : "outline"}
className="mx-1"
>
{i + 1}
</Button>
)
)}
</div>
<motion.div
variants={cardVariants}
initial="hidden"
animate="visible"
exit="exit"
layout
>
<div className="mt-8 flex justify-center">
{Array.from(
{ length: Math.ceil(filteredPostsMemo.length / POSTS_PER_PAGE) },
(_, i) => (
<Button
key={i}
onClick={() => paginate(i + 1)}
variant={currentPage === i + 1 ? "default" : "outline"}
className="mx-1"
>
{i + 1}
</Button>
)
)}
</div>
</motion.div>
)}
</div>
);
Expand Down
60 changes: 60 additions & 0 deletions src/app/blog/[id]/AnimatedBlogPost.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.5 }}
className="container mx-auto px-4 py-8"
>
<div className="flex flex-col md:flex-row gap-8">
<aside className="md:w-1/4">
<motion.div
initial={{ x: -50, opacity: 0 }}
animate={{ x: 0, opacity: 1 }}
transition={{ duration: 0.5, delay: 0.2 }}
>
<TableOfContents headings={headings} />
</motion.div>
</aside>
<motion.article
className="md:w-3/4"
initial={{ y: 50, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
transition={{ duration: 0.5, delay: 0.3 }}
>
<BlogHeader post={post} readingTime={readingTime} />
<BlogContent content={post.content} components={mdxComponents} />
<BlogFooter post={post} />
<RelatedPosts posts={relatedPosts} />
<ShareButtons
url={`https://yourblog.com/blog/${post.id}`}
title={post.title}
/>
<div className="mt-16">
<Comments />
</div>
</motion.article>
</div>
</motion.div>
);
}
1 change: 1 addition & 0 deletions src/app/blog/[id]/MdxComponents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export const mdxComponents: MDXComponents = {
customStyle={{
backgroundColor: "var(--code-bg)",
color: "var(--code-text)",
paddingRight: "7rem",
}}
{...props}
/>
Expand Down
45 changes: 13 additions & 32 deletions src/app/blog/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -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 };
Expand Down Expand Up @@ -42,29 +38,14 @@ export default async function BlogPost({ params }: BlogPostParams) {
.slice(0, 3);

return (
<div className="container mx-auto px-4 py-8">
<>
<ReadingProgress />
<div className="flex flex-col md:flex-row gap-8">
<aside className="md:w-1/4">
<TableOfContents headings={headings} />
</aside>
<article className="md:w-3/4">
<BlogHeader post={post} readingTime={readingTime} />
<BlogContent
content={post.content}
components={mdxComponents}
/>
<BlogFooter post={post} />
<RelatedPosts posts={relatedPosts} />
<ShareButtons
url={`https://yourblog.com/blog/${post.id}`}
title={post.title}
/>
<div className="mt-16">
<Comments />
</div>
</article>
</div>
</div>
<AnimatedBlogPost
post={post}
headings={headings}
readingTime={readingTime}
relatedPosts={relatedPosts}
/>
</>
);
}
7 changes: 6 additions & 1 deletion src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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" });

Expand All @@ -31,7 +32,11 @@ export default function RootLayout({
>
<ThemeProvider attribute="class">
<Header />
<main className="flex-grow container mx-auto px-4">{children}</main>
<AnimatedLayout>
<main className="flex-grow container mx-auto px-4 h-full">
{children}
</main>
</AnimatedLayout>
<Footer />
</ThemeProvider>
</body>
Expand Down
Loading

0 comments on commit 93fb7c6

Please sign in to comment.