Blog and projects animation
This commit is contained in:
+13
-23
@@ -39,9 +39,8 @@ export default function Blog() {
|
|||||||
: projects.filter((p) => p.category === activeFilter);
|
: projects.filter((p) => p.category === activeFilter);
|
||||||
|
|
||||||
const containerVariants = {
|
const containerVariants = {
|
||||||
hidden: { opacity: 0 },
|
hidden: {},
|
||||||
visible: {
|
visible: {
|
||||||
opacity: 1,
|
|
||||||
transition: {
|
transition: {
|
||||||
staggerChildren: 0.1,
|
staggerChildren: 0.1,
|
||||||
},
|
},
|
||||||
@@ -49,13 +48,11 @@ export default function Blog() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const itemVariants = {
|
const itemVariants = {
|
||||||
hidden: { y: 20, opacity: 0 },
|
hidden: { opacity: 0, y: 20 },
|
||||||
visible: {
|
visible: {
|
||||||
y: 0,
|
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
transition: {
|
y: 0,
|
||||||
duration: 0.5,
|
transition: { duration: 0.9 },
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -115,22 +112,18 @@ export default function Blog() {
|
|||||||
</motion.section>
|
</motion.section>
|
||||||
|
|
||||||
{/* Blog Posts List */}
|
{/* Blog Posts List */}
|
||||||
<motion.section
|
<section className="relative z-10 px-6 py-12 max-w-5xl mx-auto">
|
||||||
className="relative z-10 px-6 py-12 max-w-5xl mx-auto"
|
|
||||||
initial="hidden"
|
|
||||||
animate="visible"
|
|
||||||
variants={containerVariants}
|
|
||||||
>
|
|
||||||
<div className="flex flex-col gap-8">
|
<div className="flex flex-col gap-8">
|
||||||
{filteredPosts.map((post, i) => (
|
{filteredPosts.map((post, i) => (
|
||||||
<motion.article
|
<motion.div
|
||||||
key={i}
|
key={i}
|
||||||
layout
|
className="relative group bg-slate-900/80 backdrop-blur border border-slate-700 rounded-2xl p-6 hover:border-purple-500/50 transition-colors"
|
||||||
className="relative group bg-slate-900/80 backdrop-blur border border-slate-700 rounded-2xl p-6 hover:border-purple-500/50 transition-all"
|
whileHover={{ y: -3, transition: { duration: 0.5 } }}
|
||||||
whileHover={{ y: -3 }}
|
variants={itemVariants}
|
||||||
|
initial="hidden"
|
||||||
|
animate="visible"
|
||||||
>
|
>
|
||||||
<div className="flex flex-col md:flex-row gap-4">
|
<div className="flex flex-col md:flex-row gap-4">
|
||||||
{/* Optional Thumbnail */}
|
|
||||||
{post.image && (
|
{post.image && (
|
||||||
<div className="shrink-0 w-full md:w-40 h-32 md:h-28 overflow-hidden rounded-xl">
|
<div className="shrink-0 w-full md:w-40 h-32 md:h-28 overflow-hidden rounded-xl">
|
||||||
<img
|
<img
|
||||||
@@ -141,7 +134,6 @@ export default function Blog() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Content */}
|
|
||||||
<div className="flex-1 flex flex-col justify-between">
|
<div className="flex-1 flex flex-col justify-between">
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-2xl font-bold mb-2 group-hover:text-purple-400 transition-colors">
|
<h3 className="text-2xl font-bold mb-2 group-hover:text-purple-400 transition-colors">
|
||||||
@@ -151,7 +143,6 @@ export default function Blog() {
|
|||||||
{post.description}
|
{post.description}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{/* Metadata */}
|
|
||||||
<div className="flex flex-wrap items-center gap-3 text-sm text-slate-400 mb-4">
|
<div className="flex flex-wrap items-center gap-3 text-sm text-slate-400 mb-4">
|
||||||
<span>{post.author}</span>
|
<span>{post.author}</span>
|
||||||
<span>•</span>
|
<span>•</span>
|
||||||
@@ -173,7 +164,6 @@ export default function Blog() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Read More */}
|
|
||||||
<a
|
<a
|
||||||
href={post.url}
|
href={post.url}
|
||||||
className="self-start mt-auto inline-flex items-center gap-2 px-4 py-2 bg-purple-500/10 hover:bg-purple-500/20 border border-purple-500/20 rounded-lg text-sm font-medium text-purple-400 transition-colors"
|
className="self-start mt-auto inline-flex items-center gap-2 px-4 py-2 bg-purple-500/10 hover:bg-purple-500/20 border border-purple-500/20 rounded-lg text-sm font-medium text-purple-400 transition-colors"
|
||||||
@@ -182,10 +172,10 @@ export default function Blog() {
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</motion.article>
|
</motion.div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</motion.section>
|
</section>
|
||||||
</WebStuff>
|
</WebStuff>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -140,8 +140,11 @@ export default function Projects() {
|
|||||||
key={i}
|
key={i}
|
||||||
layout
|
layout
|
||||||
className="relative group"
|
className="relative group"
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.6, ease: "easeOut" }}
|
||||||
|
viewport={{ once: true, amount: 0.3 }}
|
||||||
whileHover={{ y: -8 }}
|
whileHover={{ y: -8 }}
|
||||||
viewport={{ once: false }}
|
|
||||||
>
|
>
|
||||||
<div className="absolute inset-0 bg-linear-to-r from-purple-500/20 to-blue-500/20 rounded-2xl blur-xl group-hover:blur-2xl transition-all" />
|
<div className="absolute inset-0 bg-linear-to-r from-purple-500/20 to-blue-500/20 rounded-2xl blur-xl group-hover:blur-2xl transition-all" />
|
||||||
<div className="relative bg-slate-900/80 backdrop-blur border border-slate-700 hover:border-purple-500/50 rounded-2xl p-6 transition-all h-full flex flex-col">
|
<div className="relative bg-slate-900/80 backdrop-blur border border-slate-700 hover:border-purple-500/50 rounded-2xl p-6 transition-all h-full flex flex-col">
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
export default function formatNumber(num: number): string {
|
export default function formatNumber(num: number): string {
|
||||||
|
if (num === null) return num;
|
||||||
if (num < 1000) return num.toString();
|
if (num < 1000) return num.toString();
|
||||||
if (num < 1_000_000)
|
if (num < 1_000_000)
|
||||||
return (num / 1000).toFixed(num % 1000 === 0 ? 0 : 1) + "k";
|
return (num / 1000).toFixed(num % 1000 === 0 ? 0 : 1) + "k";
|
||||||
|
|||||||
Reference in New Issue
Block a user