Skip to content

Commit

Permalink
✨ optimize: 渲染性能优化
Browse files Browse the repository at this point in the history
  • Loading branch information
B1ue1nWh1te committed Nov 7, 2024
1 parent 9db8611 commit c919c53
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 97 deletions.
144 changes: 82 additions & 62 deletions app/components/Profile.tsx
Original file line number Diff line number Diff line change
@@ -1,69 +1,100 @@
"use client";

import { SocialLinksDock } from "@/components/SocialLinksDock";
import AnimatedGradientText from "@/components/ui/animated-gradient-text";
import { profileInfo } from "@/constants/info";
import { showConfetti } from "@/lib/utils";
import { Card, Image } from "@nextui-org/react";
import { useEffect, useState } from "react";
import { memo, useEffect, useState } from "react";

const LABELS_GRADIENT_COLORS = [
{
from: "#60a5fa",
via: "#a78bfa",
to: "#f472b6",
},
{
from: "#a78bfa",
via: "#f472b6",
to: "#fb923c",
},
{
from: "#22d3ee",
via: "#60a5fa",
to: "#a78bfa",
},
];
const Labels = memo(function Labels() {
const LABELS_GRADIENT_COLORS = [
{
from: "#60a5fa",
via: "#a78bfa",
to: "#f472b6",
},
{
from: "#a78bfa",
via: "#f472b6",
to: "#fb923c",
},
{
from: "#22d3ee",
via: "#60a5fa",
to: "#a78bfa",
},
];

export default function Profile() {
return (
<div className="flex flex-col items-center justify-center space-y-3 md:flex-row md:space-x-2 md:space-y-0">
{profileInfo.labels.map((label, index) => (
<div key={label} className="relative rounded-full">
<div
className="absolute inset-0 rounded-full"
style={{
background: `linear-gradient(to left, ${LABELS_GRADIENT_COLORS[index].from}, ${LABELS_GRADIENT_COLORS[index].via}, ${LABELS_GRADIENT_COLORS[index].to})`,
padding: "1px",
content: '""',
mask: "linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)",
maskComposite: "exclude",
WebkitMask:
"linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)",
WebkitMaskComposite: "xor",
}}
/>
<p
className="relative inline-block whitespace-nowrap bg-gradient-to-l bg-[length:var(--bg-size)_100%] bg-clip-text px-3 text-transparent"
style={{
backgroundImage: `linear-gradient(to left, ${LABELS_GRADIENT_COLORS[index].from}, ${LABELS_GRADIENT_COLORS[index].via}, ${LABELS_GRADIENT_COLORS[index].to})`,
}}
>
{label}
</p>
</div>
))}
</div>
);
});

Labels.displayName = "Labels";

const TypingText = memo(function TypingText() {
const [currentMottoIndex, setCurrentMottoIndex] = useState(0);
const [typedText, setTypedText] = useState("");
const currentMotto = profileInfo.mottos[currentMottoIndex];

useEffect(() => {
let typingInterval: NodeJS.Timeout;
let i = 0;
const typingInterval = setInterval(() => {
if (i <= currentMotto.length) {
setTypedText(currentMotto.slice(0, i));
i++;
} else {
clearInterval(typingInterval);
}
}, 100);

const startTypingAnimation = () => {
clearInterval(typingInterval);

let i = 0;
typingInterval = setInterval(() => {
if (i <= currentMotto.length) {
setTypedText(currentMotto.slice(0, i));
i++;
} else {
clearInterval(typingInterval);
}
}, 100);
};

const switchMotto = () => {
const switchInterval = setInterval(() => {
setCurrentMottoIndex((prev) => (prev + 1) % profileInfo.mottos.length);
};

const animationInterval = setInterval(() => {
switchMotto();
startTypingAnimation();
i = 0;
}, 6000);

startTypingAnimation();

return () => {
clearInterval(animationInterval);
clearInterval(switchInterval);
clearInterval(typingInterval);
};
}, [currentMotto]);

return (
<p className="h-8 bg-gradient-to-r from-blue-500 via-purple-500 to-pink-500 bg-clip-text text-lg text-transparent">
{typedText}
</p>
);
});

TypingText.displayName = "TypingText";

const Profile = memo(function Profile() {
return (
<Card
className="flex min-w-[24rem] flex-[2] select-none items-center justify-center bg-white/60 p-6 backdrop-blur-lg transition-all duration-300 hover:shadow-lg hover:shadow-[#a78bfa]/25 hover:ring-2 hover:ring-[#a78bfa]/50"
Expand All @@ -83,25 +114,14 @@ export default function Profile() {
<h1 className="text-2xl font-bold text-gray-600">
{profileInfo.nickname}
</h1>
<div className="flex flex-col items-center justify-center space-y-3 md:flex-row md:space-x-3 md:space-y-0">
{profileInfo.labels.map((label, index) => (
<AnimatedGradientText key={label}>
<p
className="inline whitespace-nowrap bg-gradient-to-r bg-[length:var(--bg-size)_100%] bg-clip-text text-transparent"
style={{
backgroundImage: `linear-gradient(to right, ${LABELS_GRADIENT_COLORS[index].from}, ${LABELS_GRADIENT_COLORS[index].via}, ${LABELS_GRADIENT_COLORS[index].to})`,
}}
>
{label}
</p>
</AnimatedGradientText>
))}
</div>
<p className="h-8 bg-gradient-to-r from-blue-500 via-purple-500 to-pink-500 bg-clip-text text-lg text-transparent">
{typedText}
</p>
<Labels />
<TypingText />
<SocialLinksDock />
</div>
</Card>
);
}
});

Profile.displayName = "Profile";

export default Profile;
76 changes: 41 additions & 35 deletions app/components/ProjectsBeam.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,45 +12,47 @@ import { projectsInfo } from "@/constants/info";
import { cn, showConfetti } from "@/lib/utils";
import { Card } from "@nextui-org/react";
import Image from "next/image";
import { forwardRef, useRef } from "react";
import { forwardRef, memo, useRef } from "react";

const Circle = forwardRef<
HTMLDivElement,
{ className?: string; projectName: keyof typeof projectsInfo }
>(({ className, projectName }, ref) => {
const project = projectsInfo[projectName];
const Circle = memo(
forwardRef<
HTMLDivElement,
{ className?: string; projectName: keyof typeof projectsInfo }
>(({ className, projectName }, ref) => {
const project = projectsInfo[projectName];

return (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<div
ref={ref}
className={cn(
"z-10 flex size-16 cursor-pointer items-center justify-center rounded-full border-2 bg-white p-3 shadow-[0_0_20px_-12px_rgba(0,0,0,0.8)] transition-transform hover:scale-110",
className,
)}
>
<Image
src={project.logoPath}
alt={project.name}
width={32}
height={32}
className="size-full object-contain"
/>
</div>
</TooltipTrigger>
<TooltipContent>
<p>{project.name}</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
});
return (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<div
ref={ref}
className={cn(
"z-10 flex size-16 cursor-pointer items-center justify-center rounded-full border-2 bg-white p-3 shadow-[0_0_20px_-12px_rgba(0,0,0,0.8)] transition-transform hover:scale-110",
className,
)}
>
<Image
src={project.logoPath}
alt={project.name}
width={32}
height={32}
className="size-full object-contain"
/>
</div>
</TooltipTrigger>
<TooltipContent>
<p>{project.name}</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
}),
);

Circle.displayName = "Circle";

export default function ProjectsBeam() {
const ProjectsBeam = memo(function ProjectsBeam() {
const containerRef = useRef<HTMLDivElement>(null);
const leftTopRef = useRef<HTMLDivElement>(null);
const leftBottomRef = useRef<HTMLDivElement>(null);
Expand Down Expand Up @@ -122,4 +124,8 @@ export default function ProjectsBeam() {
<Ripple mainCircleSize={120} mainCircleOpacity={0.3} numCircles={2} />
</Card>
);
}
});

ProjectsBeam.displayName = "ProjectsBeam";

export default ProjectsBeam;

0 comments on commit c919c53

Please sign in to comment.