Skip to content

Commit ddaf47f

Browse files
committed
feat(blog): improve card loading and blog page styles
1 parent 4e39001 commit ddaf47f

File tree

3 files changed

+67
-98
lines changed

3 files changed

+67
-98
lines changed

src/components/BlogCard/BlogCard.tsx

Lines changed: 27 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import Image from 'next/image'
77
import Link from 'next/link'
88
import { usePathname, useSearchParams } from 'next/navigation'
99
import posthog from 'posthog-js'
10-
import { useCallback, useRef, useState } from 'react'
10+
import { useCallback, useState } from 'react'
1111

1212
interface BlogCardProps {
1313
id: string
@@ -23,6 +23,7 @@ interface BlogCardProps {
2323
href: string
2424
reactionsLength: number
2525
commentsLength: number
26+
priority?: boolean
2627
}
2728

2829
export const BlogCard = ({
@@ -35,11 +36,10 @@ export const BlogCard = ({
3536
image,
3637
reactionsLength,
3738
commentsLength,
39+
priority = false,
3840
}: BlogCardProps) => {
3941
const pathname = usePathname()
4042
const searchParams = useSearchParams()
41-
const cardImageId = `card-image-${id}`
42-
const cardImageElementRef = useRef<HTMLDivElement>(null)
4343

4444
const [hasLike, setHasLike] = useState(false)
4545

@@ -57,15 +57,8 @@ export const BlogCard = ({
5757
setHasLike((oldState) => !oldState)
5858
}, [])
5959

60-
const handleImageOnLoad = useCallback(() => {
61-
const div = cardImageElementRef.current
62-
if (div) {
63-
div.className = `${div?.className} loaded not-blur`
64-
}
65-
}, [])
66-
6760
return (
68-
<div className="rounded-lg hover:bg-slate-100 dark:hover:bg-gray-700 overflow-hidden shadow-lg transition border-gray-400 dark:border-black hover:border-indigo-300 hover:border border bg-slate-50 dark:bg-gray-800">
61+
<div className="rounded-lg hover:bg-slate-100 dark:hover:bg-gray-700 overflow-hidden shadow-lg transition-all duration-200 border border-gray-200 dark:border-gray-700 hover:border-indigo-300 hover:shadow-xl bg-white dark:bg-gray-800">
6962
<Link
7063
href={href}
7164
onClick={() => {
@@ -76,53 +69,44 @@ export const BlogCard = ({
7669
}}
7770
>
7871
{image && (
79-
<>
80-
<div
81-
id={cardImageId}
82-
ref={cardImageElementRef}
83-
className="h-64 relative blurred-img"
84-
style={
85-
(image?.blurDataURL && {
86-
backgroundImage: `url(${image?.blurDataURL})`,
87-
backgroundRepeat: 'no-repeat',
88-
backgroundSize: 'cover',
89-
}) ||
90-
{}
91-
}
92-
>
93-
<Image
94-
className="object-cover"
95-
fill
96-
loading="lazy"
97-
onLoad={handleImageOnLoad}
98-
src={image.src}
99-
alt={image.alt || title}
100-
/>
101-
</div>
102-
</>
72+
<div className="relative aspect-video bg-gray-100 dark:bg-gray-700 overflow-hidden">
73+
<Image
74+
className="object-cover transition-transform duration-200 hover:scale-105"
75+
fill
76+
priority={priority}
77+
loading={priority ? 'eager' : 'lazy'}
78+
placeholder={image.blurDataURL ? 'blur' : 'empty'}
79+
blurDataURL={image.blurDataURL}
80+
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
81+
src={image.src}
82+
alt={image.alt || title}
83+
/>
84+
</div>
10385
)}
104-
<div className="px-6 py-4">
105-
<h2 className="font-bold text-slate-900 dark:text-white text-xl mb-2">
86+
<div className="px-6 py-4 flex flex-col gap-2">
87+
<h2 className="font-bold text-slate-900 dark:text-white text-xl mb-2 line-clamp-2">
10688
{title}
10789
</h2>
10890
<p className="text-gray-400 text-sm mb-2">
109-
{new Intl.DateTimeFormat('pt-BR', {
110-
dateStyle: 'long',
111-
}).format(new Date(publishedTime))}
91+
<time dateTime={new Date(publishedTime).toISOString()}>
92+
{new Intl.DateTimeFormat('pt-BR', {
93+
dateStyle: 'long',
94+
}).format(new Date(publishedTime))}
95+
</time>
11296
</p>
113-
<p className="text-gray-700 dark:text-slate-300 text-base">
97+
<p className="text-gray-700 dark:text-slate-300 text-sm line-clamp-3">
11498
{description}
11599
</p>
116100
</div>
117101
</Link>
118102

119-
<div className="px-6 pt-4 pb-2">
103+
<div className="px-6 pt-4 flex flex-wrap gap-2 mb-4 text-blue-800 dark:text-blue-300">
120104
{tags?.map((tag) => (
121105
<Link
122106
key={`tag-${tag}-${id}`}
123107
href={pathname + '?' + createQueryString('tag', tag)}
124108
rel="noopener nofollow"
125-
className="inline-block bg-gray-200 dark:bg-slate-400 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 dark:text-gray-800 mr-2 mb-2"
109+
className="inline-block bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-300 rounded-full px-3 py-1 text-xs font-normal hover:bg-gray-300 dark:hover:bg-slate-300 transition-colors duration-200"
126110
>
127111
#{tag}
128112
</Link>

src/pages/blog/index.tsx

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,25 @@ const Blog = ({ posts: p }: InferGetStaticPropsType<typeof getStaticProps>) => {
6262
})),
6363
}
6464

65+
const priorityPosts = posts.slice(0, 3)
66+
6567
return (
6668
<Layout>
6769
<Head>
6870
<script type="application/ld+json">
6971
{JSON.stringify(structuredData)}
7072
</script>
73+
{priorityPosts.map((post, index) =>
74+
post.data.image ? (
75+
<link
76+
key={`preload-${post.data.id}`}
77+
rel="preload"
78+
as="image"
79+
href={`/static/images/${post.data.image.src}`}
80+
crossOrigin="anonymous"
81+
/>
82+
) : null,
83+
)}
7184
</Head>
7285
<NextSeo
7386
title="Rafael Thayto - Blog"
@@ -93,19 +106,22 @@ const Blog = ({ posts: p }: InferGetStaticPropsType<typeof getStaticProps>) => {
93106
/>
94107

95108
<main className="sm:px-2 mt-8">
96-
<div className="px-4 sm:px-2">
109+
<div className="px-4 sm:px-2 mb-8 max-w-3xl mx-auto flex flex-col gap-2">
97110
<h1 className="text-4xl text-slate-900 dark:text-white font-bold m-4 text-center">
98111
Blog
99112
</h1>
100-
<h2 className="text-lg text-slate-900 dark:text-slate-400 mb-4 text-center">
113+
<p className="text-base text-slate-900 dark:text-slate-400 mb-4 font-light text-center">
101114
É aqui onde você encontra tudo que gostaria de saber, o que sabe e
102115
até o que nem sabia que queria saber! :D
103-
</h2>
116+
</p>
104117
</div>
105118

106-
<div className="flex flex-wrap justify-center">
107-
{posts?.map((post) => (
108-
<article key={post.data.title} className="my-2 sm:m-2 lg:max-w-md ">
119+
<div className="flex flex-wrap justify-center gap-4">
120+
{posts?.map((post, index) => (
121+
<article
122+
key={post.data.title}
123+
className="w-full sm:max-w-sm lg:max-w-md"
124+
>
109125
<BlogCard
110126
id={post.data.id}
111127
title={post.data.title}
@@ -124,6 +140,7 @@ const Blog = ({ posts: p }: InferGetStaticPropsType<typeof getStaticProps>) => {
124140
href={post.data.href}
125141
reactionsLength={post.data.reactionsLength}
126142
commentsLength={post.data.commentsLength}
143+
priority={index < 3}
127144
/>
128145
</article>
129146
))}

src/styles/globals.css

Lines changed: 17 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -44,66 +44,34 @@
4444
transform: scaleX(1);
4545
}
4646

47-
/* BlogCard */
48-
.blurred-img {
49-
background-repeat: no-repeat;
50-
background-size: cover;
51-
filter: blur(20px);
47+
/* BlogCard - Optimized loading */
48+
.blog-card-skeleton {
49+
background: linear-gradient(90deg,
50+
var(--skeleton-base) 0%,
51+
var(--skeleton-highlight) 50%,
52+
var(--skeleton-base) 100%);
53+
background-size: 200% 100%;
54+
animation: shimmer 1.5s infinite;
5255
}
5356

54-
.blurred-img::before {
55-
content: '';
56-
position: absolute;
57-
inset: 0;
58-
opacity: 0;
59-
animation: pulse 2.5s infinite;
60-
background-color: var(--text-color);
61-
}
62-
63-
@keyframes pulse {
57+
@keyframes shimmer {
6458
0% {
65-
opacity: 0;
66-
}
67-
68-
50% {
69-
opacity: 0.1;
59+
background-position: -200% 0;
7060
}
7161

7262
100% {
73-
opacity: 0;
63+
background-position: 200% 0;
7464
}
7565
}
7666

77-
.blurred-img.loaded::before {
78-
animation: none;
79-
content: none;
80-
}
81-
82-
.blurred-img img {
83-
opacity: 0;
84-
transition: opacity 250ms ease-in-out;
85-
}
86-
87-
.blurred-img.loaded img {
88-
opacity: 1;
89-
}
90-
91-
.blurred-img.not-blur {
92-
animation: blur 0.25s forwards;
67+
:root {
68+
--skeleton-base: #f3f4f6;
69+
--skeleton-highlight: #e5e7eb;
9370
}
9471

95-
@keyframes blur {
96-
0% {
97-
filter: blur(20px);
98-
}
99-
100-
50% {
101-
filter: blur(15px);
102-
}
103-
104-
100% {
105-
filter: blur(0px);
106-
}
72+
.dark {
73+
--skeleton-base: #374151;
74+
--skeleton-highlight: #4b5563;
10775
}
10876

10977
@keyframes fade-in {

0 commit comments

Comments
 (0)