feat(performance): optimize Core Web Vitals with CSS animations and lazy analytics
- Replace framer-motion with CSS animations in TrustBadges, AsSeenIn, ProblemSection - Create AnalyticsProvider client component for OpenPanel lazy-loading - Fix HeroVideo CLS with explicit aspect-ratio (4/3) - Remove deprecated swcMinify from next.config (enabled by default) - Add optimizePackageImports for better tree-shaking
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import { motion } from "framer-motion";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
export default function ProblemSection() {
|
||||
@@ -10,13 +9,7 @@ export default function ProblemSection() {
|
||||
return (
|
||||
<section className="py-24 bg-gradient-to-b from-[#fefcfb] to-[#faf9f7]">
|
||||
<div className="container mx-auto px-4">
|
||||
<motion.div
|
||||
className="max-w-3xl mx-auto text-center"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.6 }}
|
||||
>
|
||||
<div className="max-w-3xl mx-auto text-center animate-on-scroll">
|
||||
<span className="text-xs uppercase tracking-[0.3em] text-[#c9a962] mb-4 block font-medium">
|
||||
{t("title")}
|
||||
</span>
|
||||
@@ -27,18 +20,14 @@ export default function ProblemSection() {
|
||||
{t("description")}
|
||||
</p>
|
||||
<div className="w-16 h-1 bg-gradient-to-r from-[#c9a962] to-[#FFD700] mx-auto mt-8 rounded-full" />
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 lg:gap-8 max-w-5xl mx-auto mt-16">
|
||||
{problems.map((item, index) => (
|
||||
<motion.div
|
||||
<div
|
||||
key={index}
|
||||
className="relative text-center p-8 bg-white rounded-3xl shadow-lg border border-[#f0ede8] hover:shadow-2xl hover:border-[#c9a962]/30 transition-all duration-500 group"
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.5, delay: index * 0.1 }}
|
||||
whileHover={{ y: -5 }}
|
||||
className="relative text-center p-8 bg-white rounded-3xl shadow-lg border border-[#f0ede8] hover:shadow-2xl hover:border-[#c9a962]/30 transition-all duration-500 group animate-on-scroll"
|
||||
style={{ animationDelay: `${index * 100}ms` }}
|
||||
>
|
||||
<div className="absolute top-0 left-1/2 -translate-x-1/2 w-20 h-1 bg-gradient-to-r from-[#c9a962] to-[#FFD700] rounded-b-full opacity-0 group-hover:opacity-100 transition-opacity duration-300" />
|
||||
|
||||
@@ -61,10 +50,44 @@ export default function ProblemSection() {
|
||||
</div>
|
||||
<h3 className="text-lg font-semibold text-[#1a1a1a] mb-3">{item.problem}</h3>
|
||||
<p className="text-sm text-[#666666] leading-relaxed">{item.description}</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script dangerouslySetInnerHTML={{ __html: `
|
||||
(function() {
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
entry.target.classList.add('animate-visible');
|
||||
observer.unobserve(entry.target);
|
||||
}
|
||||
});
|
||||
}, { threshold: 0.1 });
|
||||
|
||||
document.querySelectorAll('.animate-on-scroll').forEach(el => observer.observe(el));
|
||||
})();
|
||||
`}} />
|
||||
|
||||
<style>{`
|
||||
@keyframes fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
.animate-on-scroll {
|
||||
opacity: 0;
|
||||
}
|
||||
.animate-on-scroll.animate-visible {
|
||||
animation: fadeInUp 0.5s ease-out forwards;
|
||||
}
|
||||
`}</style>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user