perf/a11y: replace raw img tags, fix alt text, aria-hidden, avif/webp
This commit is contained in:
parent
15c3194eb6
commit
534a5644bf
@ -77,6 +77,8 @@ const nextConfig = {
|
||||
cpus: 1,
|
||||
},
|
||||
images: {
|
||||
formats: ['image/avif', 'image/webp'],
|
||||
minimumCacheTTL: 3600,
|
||||
remotePatterns: [
|
||||
...[NEXT_PUBLIC_SERVER_URL].map((item) => {
|
||||
const url = new URL(item)
|
||||
@ -85,6 +87,8 @@ const nextConfig = {
|
||||
protocol: url.protocol.replace(':', ''),
|
||||
}
|
||||
}),
|
||||
{ hostname: 'img.youtube.com', protocol: 'https' },
|
||||
{ hostname: 'i.vimeocdn.com', protocol: 'https' },
|
||||
],
|
||||
},
|
||||
webpack: (webpackConfig) => {
|
||||
|
||||
@ -72,7 +72,7 @@ export const FDHeroBlockComponent: React.FC<FDHeroBlockProps> = ({
|
||||
priority
|
||||
className="absolute inset-0 w-full h-full object-cover"
|
||||
sizes="100vw"
|
||||
fallbackAlt=""
|
||||
fallbackAlt={heading || ''}
|
||||
/>
|
||||
<div className={`absolute inset-0 ${overlayClass}`} aria-hidden="true" />
|
||||
</>
|
||||
|
||||
@ -83,6 +83,7 @@ export const FDLinkCardsBlockComponent: React.FC<Props> = ({
|
||||
className="w-12 h-12 md:w-16 md:h-16 object-contain"
|
||||
sizes="64px"
|
||||
fallbackAlt=""
|
||||
aria-hidden="true"
|
||||
/>
|
||||
)}
|
||||
<h2 className={`font-joey-heavy text-fd-h1 max-w-[700px] ${hClr}`}>
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import React from 'react'
|
||||
import type { FDLocationsGridBlock as Props, Media } from '@/payload-types'
|
||||
import { FDImage } from '@/components/FDImage'
|
||||
import { fdCardRadius, fdContainer} from '@/utilities/fdTheme'
|
||||
|
||||
export const FDLocationsGridBlockComponent: React.FC<Props> = ({
|
||||
@ -65,10 +66,13 @@ export const FDLocationsGridBlockComponent: React.FC<Props> = ({
|
||||
const inner = (
|
||||
<>
|
||||
{media?.url && (
|
||||
<img
|
||||
src={media.url}
|
||||
alt={(media as any).alt || card.locationName}
|
||||
className="absolute inset-0 w-full h-full object-cover transition-transform duration-500 group-hover:scale-105"
|
||||
<FDImage
|
||||
media={media}
|
||||
size="large"
|
||||
fill
|
||||
className="object-cover transition-transform duration-500 group-hover:scale-105"
|
||||
sizes="(max-width: 640px) 100vw, (max-width: 768px) 50vw, 33vw"
|
||||
fallbackAlt={card.locationName || ''}
|
||||
/>
|
||||
)}
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-black/70 via-black/20 to-transparent transition-opacity duration-300 group-hover:opacity-0" />
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import React from 'react'
|
||||
import type { FDPartnersLogosBlock as FDPartnersLogosBlockProps, Media } from '@/payload-types'
|
||||
import { FDImage } from '@/components/FDImage'
|
||||
import { fdContainer } from '@/utilities/fdTheme'
|
||||
|
||||
export const FDPartnersLogosBlockComponent: React.FC<FDPartnersLogosBlockProps> = ({
|
||||
@ -39,10 +40,12 @@ export const FDPartnersLogosBlockComponent: React.FC<FDPartnersLogosBlockProps>
|
||||
if (!media?.url) return null
|
||||
|
||||
const logoEl = (
|
||||
<img
|
||||
src={media.url}
|
||||
alt={item.alt || ''}
|
||||
<FDImage
|
||||
media={media}
|
||||
size="medium"
|
||||
className={`h-14 sm:h-12 md:h-16 lg:h-[72px] w-auto max-w-[160px] sm:max-w-[180px] md:max-w-[220px] object-contain ${imgFilter}`}
|
||||
sizes="220px"
|
||||
fallbackAlt={item.alt || ''}
|
||||
/>
|
||||
)
|
||||
|
||||
|
||||
@ -18,6 +18,8 @@ interface FDImageProps {
|
||||
sizes?: string
|
||||
/** Fallback alt text if media has none */
|
||||
fallbackAlt?: string
|
||||
/** Hide from assistive tech (decorative images) */
|
||||
'aria-hidden'?: boolean | 'true' | 'false'
|
||||
}
|
||||
|
||||
export const FDImage: React.FC<FDImageProps> = ({
|
||||
@ -28,6 +30,7 @@ export const FDImage: React.FC<FDImageProps> = ({
|
||||
priority = false,
|
||||
sizes = '(max-width: 768px) 100vw, (max-width: 1200px) 80vw, 1200px',
|
||||
fallbackAlt = '',
|
||||
'aria-hidden': ariaHidden,
|
||||
}) => {
|
||||
// If media is not a populated object, bail
|
||||
if (!media || typeof media === 'string' || typeof media === 'number') return null
|
||||
@ -47,7 +50,7 @@ export const FDImage: React.FC<FDImageProps> = ({
|
||||
if (isSvg) {
|
||||
return (
|
||||
// eslint-disable-next-line @next/next/no-img-element
|
||||
<img src={src} alt={alt} className={className} loading="lazy" />
|
||||
<img src={src} alt={alt} className={className} loading="lazy" aria-hidden={ariaHidden} />
|
||||
)
|
||||
}
|
||||
|
||||
@ -60,6 +63,7 @@ export const FDImage: React.FC<FDImageProps> = ({
|
||||
className={className}
|
||||
priority={priority}
|
||||
sizes={sizes}
|
||||
aria-hidden={ariaHidden}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@ -78,6 +82,7 @@ export const FDImage: React.FC<FDImageProps> = ({
|
||||
className={className}
|
||||
priority={priority}
|
||||
sizes={sizes}
|
||||
aria-hidden={ariaHidden}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user