Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion next.config.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
/** @type {import('next').NextConfig} */
const nextConfig = {};
const nextConfig = {
images: {
imageSizes: [16, 32, 48, 64, 96, 128, 160, 208, 256, 320, 384, 416, 512],
deviceSizes: [
320, 375, 393, 400, 430, 480, 512, 640, 750, 828, 1080, 1200, 1920, 2048, 3840,
],
qualities: [50, 75],
},
};

export default nextConfig;
37 changes: 37 additions & 0 deletions src/components/compress-image.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* getCompressedImageProps
*
* Returns Next.js <Image> props with responsive sizes and quality.
* Use with fill for correct responsive image delivery.
*
* Usage:
* <Image src={src} alt={alt} fill {...getCompressedImageProps(208, 180)} />
*
* @param displaySizeDesktop - The largest dimension the image is rendered at (px) on desktop
* @param displaySizeMobile - The largest dimension the image is rendered at (px) on mobile
* @param quality - Compression quality 1–100 (default: 50)
*/
export function getCompressedImageProps(
displaySizeDesktop: number,
displaySizeMobile: number,
quality = 50,
) {
return {
sizes: `(max-width: 768px) ${displaySizeMobile}px, ${displaySizeDesktop}px`,
quality,
};
}

export function getCompressedBannerImageProps(
displaySizeDesktop: number,
displaySizeMobile: number,
quality = 75,
) {
return {
priority: true,
fetchPriority: 'high' as const,
loading: 'eager' as const,
sizes: `(max-width: 768px) ${displaySizeMobile}px, ${displaySizeDesktop}px`,
quality,
};
}
7 changes: 7 additions & 0 deletions src/components/page-header.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Image from 'next/image';
import { getCompressedBannerImageProps } from './compress-image';

export default function PageHeader({ title, image }: { title: string; image: string }) {
return (
Expand All @@ -10,6 +11,7 @@ export default function PageHeader({ title, image }: { title: string; image: str
fill
src={image}
alt={title}
{...getCompressedBannerImageProps(1920, 200)}
/>
<div className="w-full h-full bg-opacity-30 bg-black p-12 relative">
<div className="container z-10">
Expand All @@ -28,6 +30,11 @@ export default function PageHeader({ title, image }: { title: string; image: str
fill
src={image}
alt={title}
sizes="100vw"
quality={75}
priority
fetchPriority="high"
loading="eager"
/>
</div>
</div>
Expand Down
2 changes: 2 additions & 0 deletions src/components/profile-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Image from 'next/image';
import React from 'react';
import { motion } from 'framer-motion';
import { IProfile } from '@/data/team';
import { getCompressedImageProps } from '@/components/compress-image';

export default function ProfileCard({
profile,
Expand All @@ -28,6 +29,7 @@ export default function ProfileCard({
alt={profile?.name}
fill
className="object-cover"
{...getCompressedImageProps(208, 208)}
/>
</div>
<div className="text-center">
Expand Down
2 changes: 2 additions & 0 deletions src/components/profile-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
import Image from 'next/image';
import { IProfile } from '@/data/team';
import { useEffect, useState } from 'react';
import { getCompressedImageProps } from '@/components/compress-image';

export default function ProfileModal({
profile,
Expand Down Expand Up @@ -90,6 +91,7 @@ export default function ProfileModal({
alt={profile?.name}
fill
className="object-cover"
{...getCompressedImageProps(208, 208)}
/>
</div>

Expand Down
Loading