131 lines
6.2 KiB
TypeScript
131 lines
6.2 KiB
TypeScript
import React, { useRef, useLayoutEffect } from 'react';
|
|
import { motion } from 'framer-motion';
|
|
import gsap from 'gsap';
|
|
import { ScrollTrigger } from 'gsap/ScrollTrigger';
|
|
|
|
gsap.registerPlugin(ScrollTrigger);
|
|
|
|
const posts = [
|
|
{
|
|
image: 'https://lh3.googleusercontent.com/aida-public/AB6AXuARalmRkuoZMBAbavGQgx4a-JhLgXBJ6JSD0U4vycdwaGGV3d-ffUFrdbx2lIbKrYCmS100i7VJ0w5cDHITXYV6w1-pSUPHKL7Jik__TWOIYOnq_4ND5ri7l8SQoaJdjJK9jhYvtxdxrZm6j8t8BNAjvPTaUdUDo4C7QVqcx1KbGvup6cpF8vY1LJ82S_5OMAZ6JgH0rK5bvWpqD3WqPhtqJCUB6d_1gUvluKjotwnNQ03t1dSYV8HOtRrLE83j6i_wgL4GZ0XTsMZb',
|
|
date: 'Jan 10, 2026',
|
|
category: 'Performance',
|
|
title: 'Upgrade Your HDD to SSD for Enhanced Performance',
|
|
excerpt: 'In today\'s fast-paced digital world, the performance of your computer can make a significant difference in productivity...'
|
|
},
|
|
{
|
|
image: 'https://lh3.googleusercontent.com/aida-public/AB6AXuCz5lTYjY4RNXubQlrA-BtLIGR3nUY8ULkD9omwT5FShfdMrbMgS5dDCyfN3xiB5WC7T3vjNvyvVbvnD0G1zBpbNTjfOYyhmAEfno7Hf5W1sm-KYRXYrLGQq-c6TkLgEf0i9JGNvuFZ6edcenr2o39dCzIPXcp_z9XWOIzp7kBX2EydNPLJoRofVYuSTmEA1y0_xh4sdiRy1PykRASGLhKfN19_XLNuwyTBVKYISY7cHc-An69eZpAfhrvngu3E47rU6KuQS0k3QXBZ',
|
|
date: 'Jan 5, 2026',
|
|
category: 'Security',
|
|
title: 'Secure Your Corporate Network Access with WireGuard VPN',
|
|
excerpt: 'The safest way to access your corporate network remotely is through a secure VPN connection...'
|
|
},
|
|
{
|
|
image: 'https://lh3.googleusercontent.com/aida-public/AB6AXuCl5iOhTsCqcHnho89DkoLh0DYeuvef0pdp8k26NKzcAq7YPvWbAYARg9mCIvqGTxQGradp8zvscuuibskpz4W_nEzQQO1z7lgwKJ1Xxiw_yQOyXMLfoRNLTHXzqFUH8Q5daCAfYTb7Zl3sFjB7k8i44D6TGolzqrN05Db27Abf2TWDDzHpVSrNml4zddvxholHFxMzqDeSzQ5p77SLDSFNaYBZGR2lEdN2V9O0GzMqxbOjFmBGMW48nlrEDLDzYGv_gWI3RSqNqBl-',
|
|
date: 'Dec 28, 2025',
|
|
category: 'Infrastructure',
|
|
title: 'Virtualizing Windows Machines: Future-Proof Your Corporate Network',
|
|
excerpt: 'In October 2025, Microsoft will end support for Windows 10. Learn how virtualization can help you prepare...'
|
|
}
|
|
];
|
|
|
|
const Blog: React.FC = () => {
|
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
const imagesRef = useRef<(HTMLDivElement | null)[]>([]);
|
|
imagesRef.current = [];
|
|
|
|
useLayoutEffect(() => {
|
|
const ctx = gsap.context(() => {
|
|
imagesRef.current.forEach((imgWrapper) => {
|
|
if (!imgWrapper) return;
|
|
|
|
gsap.to(imgWrapper, {
|
|
yPercent: 30,
|
|
ease: "none",
|
|
scrollTrigger: {
|
|
trigger: imgWrapper.closest('article'),
|
|
start: "top bottom",
|
|
end: "bottom top",
|
|
scrub: true
|
|
}
|
|
});
|
|
});
|
|
}, containerRef);
|
|
|
|
return () => ctx.revert();
|
|
}, []);
|
|
|
|
return (
|
|
<motion.section
|
|
ref={containerRef}
|
|
id="blog"
|
|
initial={{ opacity: 0, y: 50 }}
|
|
whileInView={{ opacity: 1, y: 0 }}
|
|
viewport={{ once: true, margin: "-100px" }}
|
|
transition={{ duration: 0.8, ease: "easeOut" }}
|
|
className="py-24 bg-background-light dark:bg-background-dark border-t border-gray-200 dark:border-white/10 bg-[radial-gradient(ellipse_80%_50%_at_50%_-20%,rgba(0,0,0,0.05),rgba(0,0,0,0))] dark:bg-[radial-gradient(ellipse_80%_50%_at_50%_-20%,rgba(255,255,255,0.05),rgba(255,255,255,0))]"
|
|
>
|
|
<div className="max-w-7xl mx-auto px-6">
|
|
<div className="flex justify-between items-end mb-12">
|
|
<div>
|
|
<span className="text-xs font-semibold uppercase tracking-widest text-gray-500 dark:text-gray-500 mb-2 block">Latest Insights</span>
|
|
<h2 className="font-display text-3xl md:text-4xl text-gray-900 dark:text-white">
|
|
Stay updated <span className="text-gray-400 dark:text-gray-600">with our latest news and articles.</span>
|
|
</h2>
|
|
</div>
|
|
<motion.a
|
|
href="#"
|
|
className="hidden md:inline-flex items-center text-sm font-medium text-gray-900 dark:text-white hover:text-blue-600 dark:hover:text-blue-400 transition-colors"
|
|
whileHover={{ x: 5 }}
|
|
>
|
|
View all posts <span className="material-symbols-outlined text-sm ml-1">arrow_forward</span>
|
|
</motion.a>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
|
{posts.map((post, i) => (
|
|
<motion.article
|
|
key={i}
|
|
initial={{ opacity: 0, scale: 0.95 }}
|
|
whileInView={{ opacity: 1, scale: 1 }}
|
|
viewport={{ once: true }}
|
|
transition={{ duration: 0.5, delay: i * 0.1 }}
|
|
whileHover={{ y: -8 }}
|
|
className="group cursor-pointer"
|
|
>
|
|
<div className="h-64 rounded-xl overflow-hidden mb-6 relative shadow-lg">
|
|
<div
|
|
ref={el => { if (el) imagesRef.current.push(el); }}
|
|
className="w-full h-[140%] -mt-[20%]"
|
|
>
|
|
<img
|
|
src={post.image}
|
|
alt={post.title}
|
|
className="w-full h-full object-cover transition-transform duration-700 group-hover:scale-110"
|
|
/>
|
|
</div>
|
|
<div className="absolute inset-0 bg-black/20 group-hover:bg-black/10 transition-colors pointer-events-none"></div>
|
|
<div className="absolute top-4 right-4 bg-white/90 dark:bg-black/80 backdrop-blur text-xs font-bold px-3 py-1 rounded-full uppercase tracking-wider z-10">
|
|
Read
|
|
</div>
|
|
</div>
|
|
<div className="flex items-center gap-3 text-xs text-gray-500 dark:text-gray-400 mb-3">
|
|
<span>{post.date}</span>
|
|
<span className="w-1 h-1 rounded-full bg-gray-400"></span>
|
|
<span className="text-blue-600 dark:text-blue-400 font-medium">{post.category}</span>
|
|
</div>
|
|
<h3 className="text-xl font-display font-bold text-gray-900 dark:text-white mb-2 group-hover:text-blue-600 dark:group-hover:text-blue-400 transition-colors">
|
|
{post.title}
|
|
</h3>
|
|
<p className="text-sm text-gray-600 dark:text-gray-400 line-clamp-2">
|
|
{post.excerpt}
|
|
</p>
|
|
</motion.article>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</motion.section>
|
|
);
|
|
};
|
|
|
|
export default Blog; |