Skip to content

Commit a42abc1

Browse files
committed
Simplified carousel animations since it might be the cause of failure to load the images
1 parent abb5ae6 commit a42abc1

File tree

2 files changed

+43
-47
lines changed

2 files changed

+43
-47
lines changed

src/components/ProjectCarousel/index.tsx

Lines changed: 33 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import styles from './styles.module.css';
88
type Project = {
99
title: string;
1010
description: string;
11-
image: string;
11+
image: string; // path under /static, e.g. 'img/foo.png'
1212
link: string;
1313
};
1414

@@ -75,34 +75,23 @@ export default function ProjectCarousel(): ReactNode {
7575

7676
useEffect(() => {
7777
if (!isAutoPlaying) return;
78-
79-
const interval = setInterval(() => {
80-
goToNext();
81-
}, 5000);
82-
83-
return () => clearInterval(interval);
78+
const id = setInterval(goToNext, 5000);
79+
return () => clearInterval(id);
8480
}, [isAutoPlaying, goToNext]);
8581

86-
const handleMouseEnter = useCallback(() => {
87-
setIsAutoPlaying(false);
88-
}, []);
89-
90-
const handleMouseLeave = useCallback(() => {
91-
setIsAutoPlaying(true);
92-
}, []);
82+
const active = projects[currentIndex];
83+
const activeSrc = useBaseUrl(active.image);
9384

9485
return (
9586
<section className={styles.carousel}>
9687
<div className="container">
9788
<Heading as="h2" className={styles.title}>TeXlyre Ecosystem</Heading>
98-
<p className={styles.subtitle}>
99-
Explore the open-source projects that power TeXlyre
100-
</p>
89+
<p className={styles.subtitle}>Explore the open-source projects that power TeXlyre</p>
10190

10291
<div
10392
className={styles.carouselContainer}
104-
onMouseEnter={handleMouseEnter}
105-
onMouseLeave={handleMouseLeave}
93+
onMouseEnter={() => setIsAutoPlaying(false)}
94+
onMouseLeave={() => setIsAutoPlaying(true)}
10695
>
10796
<button
10897
className={clsx(styles.navButton, styles.navButtonPrev)}
@@ -113,31 +102,32 @@ export default function ProjectCarousel(): ReactNode {
113102
</button>
114103

115104
<div className={styles.carouselContent}>
116-
{projects.map((project, index) => (
117-
<div
118-
key={index}
119-
className={clsx(styles.slide, {
120-
[styles.slideActive]: index === currentIndex,
121-
})}
105+
{/* Only render the active slide */}
106+
<div className={clsx(styles.slide, styles.slideActive)}>
107+
<a
108+
href={active.link}
109+
target="_blank"
110+
rel="noopener noreferrer"
111+
className={styles.slideLink}
122112
>
123-
<a
124-
href={project.link}
125-
target="_blank"
126-
rel="noopener noreferrer"
127-
className={styles.slideLink}
128-
>
129-
<img
130-
src={useBaseUrl(project.image)}
131-
alt={project.title}
132-
className={styles.slideImage}
133-
/>
134-
<div className={styles.slideInfo}>
135-
<h3 className={styles.slideTitle}>{project.title}</h3>
136-
<p className={styles.slideDescription}>{project.description}</p>
137-
</div>
138-
</a>
139-
</div>
140-
))}
113+
<img
114+
src={activeSrc}
115+
alt={active.title}
116+
className={styles.slideImage}
117+
decoding="async"
118+
loading="eager" // ensure it loads even inside a hidden-ish container
119+
onError={(e) => {
120+
// Helpful in prod if something blocks images unexpectedly
121+
// eslint-disable-next-line no-console
122+
console.warn('Carousel image failed to load:', (e.target as HTMLImageElement).src);
123+
}}
124+
/>
125+
<div className={styles.slideInfo}>
126+
<h3 className={styles.slideTitle}>{active.title}</h3>
127+
<p className={styles.slideDescription}>{active.description}</p>
128+
</div>
129+
</a>
130+
</div>
141131
</div>
142132

143133
<button

src/components/ProjectCarousel/styles.module.css

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,14 @@
2525
position: relative;
2626
max-width: 1100px;
2727
margin: 0 auto;
28+
isolation: isolate;
2829
}
2930

3031
.carouselContent {
3132
position: relative;
3233
width: 100%;
33-
aspect-ratio: 1320 / 1080;
34+
aspect-ratio: 16 / 9;
35+
min-height: 220px;
3436
overflow: hidden;
3537
border-radius: 12px;
3638
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1);
@@ -49,11 +51,15 @@
4951
opacity: 0;
5052
transform: translateX(100%);
5153
transition: opacity 0.5s ease-in-out, transform 0.5s ease-in-out;
54+
pointer-events: none;
55+
z-index: 1;
5256
}
5357

5458
.slideActive {
55-
opacity: 1;
56-
transform: translateX(0);
59+
opacity: 1 !important;
60+
transform: translateX(0) !important;
61+
pointer-events: auto;
62+
z-index: 2;
5763
}
5864

5965
.slideLink {
@@ -67,7 +73,7 @@
6773
.slideImage {
6874
width: 100%;
6975
height: 100%;
70-
object-fit: cover;
76+
object-fit: contain;
7177
display: block;
7278
}
7379

0 commit comments

Comments
 (0)