diff --git a/app/components/RelatedArticles/RelatedArticles.container.tsx b/app/components/RelatedArticles/RelatedArticles.container.tsx index abbe0d8..b0fe4bd 100644 --- a/app/components/RelatedArticles/RelatedArticles.container.tsx +++ b/app/components/RelatedArticles/RelatedArticles.container.tsx @@ -15,14 +15,8 @@ const RelatedArticlesContainer = memo( const [currentIndex, setCurrentIndex] = useState(0); const [progress, setProgress] = useState(0); - const [mounted, setMounted] = useState(false); const isMobile = useIsMobile(); - // Ensure hydration matches server render - useEffect(() => { - setMounted(true); - }, []); - // Memoize the mouse down handler to prevent unnecessary re-renders const handleMouseDown = useCallback( (e: React.MouseEvent) => { @@ -48,17 +42,16 @@ const RelatedArticlesContainer = memo( ); // Memoize transform style to prevent unnecessary recalculations - // Use mounted state to prevent hydration mismatch const transformStyle = useMemo( () => ({ - transform: mounted && isMobile + transform: isMobile ? `translateX(calc(50% - 130px - ${currentIndex * 260}px))` : "none", - scrollBehavior: (mounted && !isMobile + scrollBehavior: (!isMobile ? "smooth" : "auto") as React.CSSProperties["scrollBehavior"], }), - [mounted, isMobile, currentIndex], + [isMobile, currentIndex], ); // Memoize progress bar style calculation @@ -74,9 +67,9 @@ const RelatedArticlesContainer = memo( [currentIndex, progress], ); - // Auto-advance every 3 seconds (only on mobile, after mount) + // Auto-advance every 3 seconds (only on mobile) useEffect(() => { - if (filteredPosts.length <= 1 || !mounted || !isMobile) return; + if (filteredPosts.length <= 1 || !isMobile) return; const interval = setInterval(() => { setProgress(0); @@ -84,11 +77,11 @@ const RelatedArticlesContainer = memo( }, 3000); return () => clearInterval(interval); - }, [filteredPosts.length, mounted, isMobile]); + }, [filteredPosts.length, isMobile]); - // Progress animation (only on mobile, after mount) + // Progress animation (only on mobile) useEffect(() => { - if (filteredPosts.length <= 1 || !mounted || !isMobile) return; + if (filteredPosts.length <= 1 || !isMobile) return; const progressInterval = setInterval(() => { setProgress((prev) => { @@ -100,13 +93,13 @@ const RelatedArticlesContainer = memo( }, 30); // 30ms intervals for smooth animation return () => clearInterval(progressInterval); - }, [currentIndex, filteredPosts.length, mounted, isMobile]); + }, [currentIndex, filteredPosts.length, isMobile]); return ( - {/* Progress bars - only show on mobile (after hydration) */} + {/* Progress bars - only show on mobile */} {isMobile && (
{filteredPosts.map((relatedPost, index) => ( diff --git a/app/tailwind.css b/app/tailwind.css index 9952f8e..7642f27 100644 --- a/app/tailwind.css +++ b/app/tailwind.css @@ -492,9 +492,15 @@ --color-border-default-utility-warning: var(--color-yellow-yellow300); /* Theme-dark aliases for utility tokens */ - --color-border-default-negative-primary: var(--color-border-default-utility-negative); - --color-border-default-warning-primary: var(--color-border-default-utility-warning); - --color-border-default-positive-primary: var(--color-border-default-utility-positive); + --color-border-default-negative-primary: var( + --color-border-default-utility-negative + ); + --color-border-default-warning-primary: var( + --color-border-default-utility-warning + ); + --color-border-default-positive-primary: var( + --color-border-default-utility-positive + ); /* Theme-light variants */ --color-border-default-negative-primary-light: var(--color-red-red300); @@ -568,9 +574,15 @@ --color-content-default-utility-warning: var(--color-yellow-yellow500); /* Theme-dark aliases for utility tokens */ - --color-content-default-negative-primary: var(--color-content-default-utility-negative); - --color-content-default-warning-primary: var(--color-content-default-utility-warning); - --color-content-default-positive-primary: var(--color-content-default-utility-positive); + --color-content-default-negative-primary: var( + --color-content-default-utility-negative + ); + --color-content-default-warning-primary: var( + --color-content-default-utility-warning + ); + --color-content-default-positive-primary: var( + --color-content-default-utility-positive + ); /* Theme-light variants */ --color-content-default-negative-primary-light: var(--color-red-red500); @@ -583,11 +595,15 @@ --color-content-default-tertiary-light: var(--color-gray-700); --color-content-default-brand-lime-light: var(--color-lime-lime600); --color-content-default-brand-rust-light: var(--color-rust-rust500); - --color-content-default-brand-royal-light: var(--color-royal-blue-royal-blue1000); + --color-content-default-brand-royal-light: var( + --color-royal-blue-royal-blue1000 + ); --color-content-default-brand-red-light: var(--color-red-red500); --color-content-default-brand-teal-light: var(--color-teal-teal500); --color-content-default-brand-kiwi-light: var(--color-kiwi-kiwi600); - --color-content-default-brand-lavender-light: var(--color-lavender-lavender500); + --color-content-default-brand-lavender-light: var( + --color-lavender-lavender500 + ); --color-content-inverse-brand-accent: var(--color-yellow-yellow700); --color-content-inverse-brand-primary: var(--color-yellow-yellow900); @@ -625,10 +641,14 @@ --color-content-invert-brand-primary-light: var(--color-yellow-yellow50); --color-content-invert-brand-secondary-light: var(--color-yellow-yellow200); --color-content-invert-brand-lime-light: var(--color-lime-lime200); - --color-content-invert-brand-royal-light: var(--color-royal-blue-royal-blue200); + --color-content-invert-brand-royal-light: var( + --color-royal-blue-royal-blue200 + ); --color-content-invert-brand-teal-light: var(--color-teal-teal200); --color-content-invert-brand-rust-light: var(--color-rust-rust150); - --color-content-invert-brand-lavender-light: var(--color-lavender-lavender150); + --color-content-invert-brand-lavender-light: var( + --color-lavender-lavender150 + ); --color-content-invert-brand-kiwi-light: var(--color-kiwi-kiwi100); --color-content-invert-brand-red-light: var(--color-red-red100); --color-content-invert-positive-primary-light: var(--color-kiwi-kiwi300); @@ -649,12 +669,16 @@ --color-surface-default-brand-teal: var(--color-teal-teal50); /* Theme-dark brand token variants */ - --color-surface-default-brand-royal-dark: var(--color-royal-blue-royal-blue800); + --color-surface-default-brand-royal-dark: var( + --color-royal-blue-royal-blue800 + ); --color-surface-default-brand-lime-dark: var(--color-lime-lime800); --color-surface-default-brand-rust-dark: var(--color-rust-rust700); --color-surface-default-brand-red-dark: var(--color-red-red700); --color-surface-default-brand-kiwi-dark: var(--color-kiwi-kiwi700); - --color-surface-default-brand-lavender-dark: var(--color-lavender-lavender700); + --color-surface-default-brand-lavender-dark: var( + --color-lavender-lavender700 + ); --color-surface-default-brand-teal-dark: var(--color-teal-teal700); --color-surface-default-positive-secondary: var(--color-kiwi-kiwi1000); --color-surface-default-warning-secondary: var(--color-yellow-yellow1000); @@ -672,9 +696,15 @@ --color-surface-default-utility-warning: var(--color-yellow-yellow500); /* Theme-dark aliases for utility tokens */ - --color-surface-default-negative-primary: var(--color-surface-default-utility-negative); - --color-surface-default-warning-primary: var(--color-surface-default-utility-warning); - --color-surface-default-positive-primary: var(--color-surface-default-utility-positive); + --color-surface-default-negative-primary: var( + --color-surface-default-utility-negative + ); + --color-surface-default-warning-primary: var( + --color-surface-default-utility-warning + ); + --color-surface-default-positive-primary: var( + --color-surface-default-utility-positive + ); /* Theme-light variants */ --color-surface-default-negative-primary-light: var(--color-red-red200); @@ -704,9 +734,15 @@ --color-surface-invert-primary: var(--color-surface-inverse-primary); --color-surface-invert-secondary: var(--color-surface-inverse-secondary); --color-surface-invert-tertiary: var(--color-surface-inverse-tertiary); - --color-surface-invert-brand-primary: var(--color-surface-inverse-brand-primary); - --color-surface-invert-brand-secondary: var(--color-surface-inverse-brand-secondary); - --color-surface-invert-brand-accent: var(--color-surface-inverse-brand-accent); + --color-surface-invert-brand-primary: var( + --color-surface-inverse-brand-primary + ); + --color-surface-invert-brand-secondary: var( + --color-surface-inverse-brand-secondary + ); + --color-surface-invert-brand-accent: var( + --color-surface-inverse-brand-accent + ); --color-surface-invert-brand-lime: var(--color-lime-lime100); --color-surface-invert-brand-royal: var(--color-royal-blue-royal-blue50); --color-surface-invert-brand-teal: var(--color-teal-teal50); @@ -728,16 +764,22 @@ --color-surface-invert-brand-primary-light: var(--color-yellow-yellow1000); --color-surface-invert-brand-secondary-light: var(--color-yellow-yellow800); --color-surface-invert-brand-lime-light: var(--color-lime-lime800); - --color-surface-invert-brand-royal-light: var(--color-royal-blue-royal-blue800); + --color-surface-invert-brand-royal-light: var( + --color-royal-blue-royal-blue800 + ); --color-surface-invert-brand-teal-light: var(--color-teal-teal700); --color-surface-invert-brand-rust-light: var(--color-rust-rust700); - --color-surface-invert-brand-lavender-light: var(--color-lavender-lavender700); + --color-surface-invert-brand-lavender-light: var( + --color-lavender-lavender700 + ); --color-surface-invert-brand-kiwi-light: var(--color-kiwi-kiwi700); --color-surface-invert-brand-red-light: var(--color-red-red700); --color-surface-invert-negative-primary-light: var(--color-red-red400); --color-surface-invert-negative-secondary-light: var(--color-red-red1000); --color-surface-invert-warning-primary-light: var(--color-yellow-yellow500); - --color-surface-invert-warning-secondary-light: var(--color-yellow-yellow1000); + --color-surface-invert-warning-secondary-light: var( + --color-yellow-yellow1000 + ); --color-surface-invert-positive-primary-light: var(--color-kiwi-kiwi500); --color-surface-invert-positive-secondary-light: var(--color-kiwi-kiwi1000); diff --git a/tests/e2e/visual-regression.spec.ts-snapshots/homepage-full-chromium.png b/tests/e2e/visual-regression.spec.ts-snapshots/homepage-full-chromium.png index 888b9f0..b1df06b 100644 Binary files a/tests/e2e/visual-regression.spec.ts-snapshots/homepage-full-chromium.png and b/tests/e2e/visual-regression.spec.ts-snapshots/homepage-full-chromium.png differ diff --git a/tests/e2e/visual-regression.spec.ts-snapshots/homepage-full-firefox.png b/tests/e2e/visual-regression.spec.ts-snapshots/homepage-full-firefox.png index fdf6b00..0ba2e7b 100644 Binary files a/tests/e2e/visual-regression.spec.ts-snapshots/homepage-full-firefox.png and b/tests/e2e/visual-regression.spec.ts-snapshots/homepage-full-firefox.png differ diff --git a/tests/e2e/visual-regression.spec.ts-snapshots/homepage-full-webkit.png b/tests/e2e/visual-regression.spec.ts-snapshots/homepage-full-webkit.png index 4b501a0..c62b460 100644 Binary files a/tests/e2e/visual-regression.spec.ts-snapshots/homepage-full-webkit.png and b/tests/e2e/visual-regression.spec.ts-snapshots/homepage-full-webkit.png differ