Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: ✨ 减少动画,增加回到顶部 #13

Merged
merged 1 commit into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/app/about/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,23 @@ export default function About() {

return (
<div
className={`max-w-4xl mx-auto rounded-lg shadow-lg p-8 my-10
className={`max-w-4xl mx-auto rounded-lg shadow-lg p-8 my-10 transition-all duration-300 ease-in-out
${
theme === "dark"
? "bg-gray-800 text-white"
: "bg-gradient-to-br from-blue-50 to-indigo-100 text-gray-800"
}`}
>
<h1
className={`text-4xl font-bold mb-6 ${
className={`text-4xl font-bold mb-6 transition-colors duration-300 ${
theme === "dark" ? "text-indigo-300" : "text-indigo-800"
}`}
>
关于我的博客
</h1>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
<div
className={`md:col-span-2 prose lg:prose-xl ${
className={`md:col-span-2 prose lg:prose-xl transition-all duration-300 ${
theme === "dark" ? "text-gray-300" : "text-gray-700"
}`}
>
Expand All @@ -43,7 +43,7 @@ export default function About() {
如果你有任何问题、建议或合作意向,欢迎随时与我联系。让我们一起在编程的世界里探索和创新!
</p>
</div>
<div className="flex flex-col items-center justify-center">
<div className="flex flex-col items-center justify-center transition-transform duration-300 hover:scale-105">
<Image
src="/img/avatar.png"
alt="博主头像"
Expand Down
30 changes: 8 additions & 22 deletions src/app/blog/[id]/AnimatedBlogPost.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
"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 ScrollToTop from "@/components/blog/id/ScrollToTop";
import Comments from "@/components/blog/id/Comments";
import { mdxComponents } from "./MdxComponents";
import type { Heading } from "./types";
Expand All @@ -32,29 +32,14 @@ export default function AnimatedBlogPost({
relatedPosts,
}: AnimatedBlogPostProps) {
return (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.5 }}
className="container mx-auto px-4 py-8 text-gray-900 dark:text-gray-100 bg-white dark:bg-gray-800"
>
<div className="container mx-auto px-4 py-8 text-gray-900 dark:text-gray-100 bg-white dark:bg-gray-800">
<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 }}
className="sticky top-20"
>
<div className="sticky top-20">
<TableOfContents headings={headings} />
</motion.div>
</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 }}
>
<article className="md:w-3/4">
<BlogHeader
post={post}
readingTime={readingTime}
Expand All @@ -74,8 +59,9 @@ export default function AnimatedBlogPost({
<div className="mt-16">
<Comments />
</div>
</motion.article>
</article>
<ScrollToTop />
</div>
</motion.div>
</div>
);
}
4 changes: 2 additions & 2 deletions src/app/blog/[id]/MdxComponents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,14 @@ export const mdxComponents: MDXComponents = {
h2: (props: any) => (
<h2
id={props.children.toString().toLowerCase().replace(/\s+/g, "-")}
className="relative text-2xl font-semibold mt-6 mb-3 text-gray-800 dark:text-gray-200 scroll-mt-20 cursor-pointer before:content-['#'] before:absolute before:-left-6 before:opacity-0 hover:before:opacity-100 before:text-gray-800 dark:before:text-gray-200" // 设置 # 符号颜色与字体对齐
className="relative text-2xl font-semibold mt-6 mb-3 text-gray-800 dark:text-gray-200 scroll-mt-20 cursor-pointer before:content-['#'] before:absolute before:-left-6 before:opacity-0 hover:before:opacity-100 before:text-blue-500 dark:before:text-blue-400" // 设置 # 符号颜色与字体对齐
{...props}
/>
),
h3: (props: any) => (
<h3
id={props.children.toString().toLowerCase().replace(/\s+/g, "-")}
className="relative text-xl font-medium mt-4 mb-2 text-gray-700 dark:text-gray-300 scroll-mt-20 cursor-pointer before:content-['#'] before:absolute before:-left-6 before:opacity-0 hover:before:opacity-100 before:text-gray-700 dark:before:text-gray-300" // 设置 # 符号颜色与字体对齐
className="relative text-xl font-medium mt-4 mb-2 text-gray-700 dark:text-gray-300 scroll-mt-20 cursor-pointer before:content-['#'] before:absolute before:-left-6 before:opacity-0 hover:before:opacity-100 before:text-blue-500 dark:before:text-blue-400" // 设置 # 符号颜色与字体对齐
{...props}
/>
),
Expand Down
37 changes: 3 additions & 34 deletions src/components/app/AnimatedLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,7 @@
"use client";

import {
LazyMotion,
domAnimation,
motion,
AnimatePresence,
} from "framer-motion";
import { usePathname } from "next/navigation";
import React, { ReactNode } from "react";

const pageVariants = {
initial: { opacity: 0, x: "-100%" },
in: { opacity: 1, x: 0 },
// out: { opacity: 0, x: "100%" },
};

const pageTransition = {
type: "tween",
ease: "anticipate",
duration: 0.5,
};

interface AnimatedLayoutProps {
children: ReactNode;
}
Expand All @@ -29,20 +10,8 @@ export default function AnimatedLayout({ children }: AnimatedLayoutProps) {
const pathname = usePathname();

return (
<LazyMotion features={domAnimation}>
<AnimatePresence mode="wait">
<motion.main
key={pathname}
initial="initial"
animate="in"
exit="out"
variants={pageVariants}
// transition={pageTransition}
className="flex-grow container mx-auto px-4 mt-16"
>
{children}
</motion.main>
</AnimatePresence>
</LazyMotion>
<main key={pathname} className="flex-grow container mx-auto px-4 mt-16">
{children}
</main>
);
}
10 changes: 7 additions & 3 deletions src/components/app/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,24 @@ export default function Footer() {
{ href: "/contact", label: "联系我们" },
];

const buildYear = 2024; // 建站年份
const currentYear = new Date().getFullYear(); // 当前年份
const isNew = currentYear === buildYear; // 判断是否为新建站

return (
<footer className="border-t py-6 md:py-0">
<footer className="border-t py-6 md:py-0 bg-gray-100">
<div className="container flex flex-col items-center justify-between gap-4 md:h-24 md:flex-row">
<div className="flex flex-col items-center gap-4 px-8 md:flex-row md:gap-2 md:px-0">
<p className="text-center text-sm leading-loose text-muted-foreground md:text-left">
&copy; 2024 我的博客. 保留所有权利。
&copy; {currentYear} 我的博客. 保留所有权利。{isNew ? "新建站" : `建站时间: ${buildYear}年`},感谢您的访问!
</p>
</div>
<nav className="flex items-center space-x-4">
{links.map((link) => (
<Link
key={link.href}
href={link.href}
className="text-sm text-muted-foreground"
className="text-sm text-muted-foreground hover:text-blue-500 transition duration-200" // 增加过渡效果
>
<Badge>{link.label}</Badge>
</Link>
Expand Down
26 changes: 13 additions & 13 deletions src/components/app/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,20 @@ interface LayoutProps {
}

export default function Layout({ children }: LayoutProps) {
const [showScrollTop, setShowScrollTop] = useState(false);
// const [showScrollTop, setShowScrollTop] = useState(false);

useEffect(() => {
const handleScroll = debounce(() => {
setShowScrollTop(window.pageYOffset > 300);
}, 100);
// useEffect(() => {
// const handleScroll = debounce(() => {
// setShowScrollTop(window.pageYOffset > 300);
// }, 100);

window.addEventListener("scroll", handleScroll);
return () => window.removeEventListener("scroll", handleScroll);
}, []);
// window.addEventListener("scroll", handleScroll);
// return () => window.removeEventListener("scroll", handleScroll);
// }, []);

const scrollToTop = () => {
window.scrollTo({ top: 0, behavior: "smooth" });
};
// const scrollToTop = () => {
// window.scrollTo({ top: 0, behavior: "smooth" });
// };

return (
<div className="flex flex-col min-h-screen bg-gray-50 dark:bg-gray-900 text-gray-800 dark:text-gray-200">
Expand All @@ -30,15 +30,15 @@ export default function Layout({ children }: LayoutProps) {
{children}
</main>
<Footer />
{showScrollTop && (
{/* {showScrollTop && (
<button
onClick={scrollToTop}
className="fixed bottom-8 right-8 bg-blue-500 hover:bg-blue-600 text-white p-2 rounded-full shadow-lg transition-opacity duration-300 ease-in-out"
aria-label="滚动到顶部"
>
</button>
)}
)} */}
</div>
);
}
36 changes: 36 additions & 0 deletions src/components/blog/id/ScrollToTop.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"use client";
import React, { useState, useCallback, useEffect } from "react";
import { debounce } from "lodash-es";

export default function ScrollToTop() {
const [showScroll, setShowScroll] = useState(false);

const handleScroll = useCallback(
() => setShowScroll(window.scrollY > 500),
[]
);

useEffect(() => {
window.addEventListener("scroll", handleScroll);
setShowScroll(false);
return () => window.removeEventListener("scroll", handleScroll);
}, [handleScroll]);

const scrollToTop = useCallback(() => {
window.scrollTo({ top: 0, behavior: "smooth" });
}, []);

return (
<>
{showScroll && (
<button
onClick={scrollToTop}
className="fixed bottom-4 right-4 p-2 bg-gray-800 text-white rounded-full shadow-lg transition-opacity duration-300" // 添加过渡效果
style={{ visibility: showScroll ? "visible" : "hidden" }} // 使用visibility控制显示
>
回到顶部
</button>
)}
</>
);
}