11import { cn } from "@/lib/utils" ;
22import { publicAssetPath } from "@/lib/publicAsset" ;
33import { useTheme } from "next-themes" ;
4- import { useEffect , useState } from "react" ;
4+ import { useEffect , useRef , useState } from "react" ;
55
6- const heroAssetPath = ( theme : "light" | "dark" , width : 800 | 1600 ) =>
6+ const heroAssetPath = ( theme : "light" | "dark" , width : 800 | 1200 | 1600 ) =>
77 publicAssetPath ( `/hero/compbio-research-atlas-${ theme } -${ width } .webp` ) ;
88
9+ const heroSrcSet = ( theme : "light" | "dark" ) =>
10+ [ 800 , 1200 , 1600 ]
11+ . map ( ( width ) => `${ heroAssetPath ( theme , width as 800 | 1200 | 1600 ) } ${ width } w` )
12+ . join ( ", " ) ;
13+
914const heroImageProps = {
1015 alt : "" ,
1116 width : 1600 ,
1217 height : 1200 ,
1318 decoding : "async" as const ,
1419 draggable : false ,
20+ fetchpriority : "high" as const ,
1521 loading : "eager" as const ,
1622 sizes : "(min-width: 1024px) 72vw, (min-width: 640px) 110vw, 135vw" ,
1723} ;
@@ -22,34 +28,42 @@ interface HeroScienceGraphicProps {
2228
2329export const HeroScienceGraphic = ( { className } : HeroScienceGraphicProps ) => {
2430 const { resolvedTheme } = useTheme ( ) ;
25- const [ mounted , setMounted ] = useState ( false ) ;
31+ const [ darkMedia , setDarkMedia ] = useState ( "(prefers-color-scheme: dark)" ) ;
32+ const themeReady = useRef ( false ) ;
2633
2734 useEffect ( ( ) => {
28- setMounted ( true ) ;
29- } , [ ] ) ;
35+ if ( ! resolvedTheme ) return ;
3036
31- const documentTheme =
32- mounted && document . documentElement . classList . contains ( "dark" )
37+ const systemTheme = window . matchMedia ( "(prefers-color-scheme: dark)" ) . matches
3338 ? "dark"
3439 : "light" ;
35- const theme = mounted && ( resolvedTheme === "dark" || ( ! resolvedTheme && documentTheme === "dark" ) )
36- ? "dark"
37- : "light" ;
40+
41+ if ( ! themeReady . current ) {
42+ themeReady . current = true ;
43+ if ( resolvedTheme === systemTheme ) return ;
44+ }
45+
46+ setDarkMedia ( resolvedTheme === "dark" ? "all" : "not all" ) ;
47+ } , [ resolvedTheme ] ) ;
3848
3949 return (
4050 < span
4151 className = { cn ( "hero-science-art block" , className ) }
4252 aria-hidden = "true"
4353 >
44- < img
45- { ...heroImageProps }
46- src = { heroAssetPath ( theme , 1600 ) }
47- srcSet = { `${ heroAssetPath ( theme , 800 ) } 800w, ${ heroAssetPath ( theme , 1600 ) } 1600w` }
48- className = { cn (
49- "h-auto w-full select-none object-contain transition-opacity duration-200" ,
50- mounted ? "opacity-100" : "opacity-0" ,
51- ) }
52- />
54+ < picture >
55+ < source
56+ media = { darkMedia }
57+ srcSet = { heroSrcSet ( "dark" ) }
58+ sizes = { heroImageProps . sizes }
59+ />
60+ < img
61+ { ...heroImageProps }
62+ src = { heroAssetPath ( "light" , 800 ) }
63+ srcSet = { heroSrcSet ( "light" ) }
64+ className = "h-auto w-full select-none object-contain"
65+ />
66+ </ picture >
5367 </ span >
5468 ) ;
5569} ;
0 commit comments