Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[UXIT-1415] Refactor Dynamic Images #700

Merged
merged 5 commits into from
Oct 11, 2024
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
17 changes: 7 additions & 10 deletions src/app/_components/ArticleHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import type { ImageProps } from '@/types/imageType'
import Image from 'next/image'

import { graphicsData } from '@/data/graphicsData'
import type { ImageProps } from '@/types/imageType'

import { buildImageSizeProp } from '@/utils/buildImageSizeProp'

import { DynamicImage } from '@/components/DynamicImage'
import { type HeadingProps, Heading } from '@/components/Heading'

type ArticleHeaderProps = {
image?: ImageProps
image: ImageProps
children?: React.ReactNode
}

Expand All @@ -20,17 +19,15 @@ export function ArticleHeader({ image, children }: ArticleHeaderProps) {
return (
<header className="space-y-6">
<div className="space-y-6">{children}</div>

<div className="relative aspect-video">
<DynamicImage
<Image
fill
priority
quality={100}
src={image?.src || ''}
alt={image?.alt || ''}
className="rounded-lg"
src={image.src}
alt={image.alt}
className="rounded-lg object-cover"
sizes={buildImageSizeProp({ startSize: '100vw', md: '680px' })}
fallback={graphicsData.imageFallback}
/>
</div>
</header>
Expand Down
60 changes: 44 additions & 16 deletions src/app/_components/Card.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,36 @@
import Image, { type ImageProps } from 'next/image'

import { ArrowUpRight } from '@phosphor-icons/react/dist/ssr'
import { clsx } from 'clsx'
import theme from 'tailwindcss/defaultTheme'

import { type CTAProps } from '@/types/ctaType'
import type { ImageObjectFit, StaticImageProps } from '@/types/imageType'

import { buildImageSizeProp } from '@/utils/buildImageSizeProp'
import { isExternalLink } from '@/utils/linkUtils'

import { AvatarGroup, type AvatarGroupProps } from '@/components/AvatarGroup'
import { CustomLink } from '@/components/CustomLink'
import { DynamicImage, type DynamicImageProps } from '@/components/DynamicImage'
import { Heading } from '@/components/Heading'
import { Icon } from '@/components/Icon'
import { Meta, type MetaDataType } from '@/components/Meta'
import { StaticImage, type StaticImageProps } from '@/components/StaticImage'
import { type TagGroupProps, TagGroup } from '@/components/TagGroup'

type CardImageProps = (StaticImageProps | ImageProps) & {
objectFit?: ImageObjectFit
padding?: boolean
priority?: boolean
sizes?: string
}

type CardProps = {
title: string | React.ReactNode
tagLabel?: TagGroupProps['label']
metaData?: MetaDataType
description?: string
cta?: CTAProps
image?: (DynamicImageProps | StaticImageProps) & { padding?: boolean }
image?: CardImageProps
borderColor?: 'brand-300' | 'brand-400' | 'brand-500' | 'brand-600'
textIsClamped?: boolean
as?: React.ElementType
Expand Down Expand Up @@ -64,7 +73,7 @@ export function Card({
borderStyles[borderColor],
)}
>
<Card.Image image={image} />
{image && <Card.Image image={image} />}
<div className="flex flex-col gap-3 p-4">
<Card.MetaAndTags tagLabel={tagLabel} metaData={metaData} />
<Card.Title title={title} />
Expand All @@ -81,26 +90,45 @@ export function Card({
)
}

Card.Image = function Image({ image }: Pick<CardProps, 'image'>) {
if (!image) return null

const { padding, ...rest } = image
const isDynamicImage = 'src' in image
Card.Image = function ImageComponent({ image }: { image: CardImageProps }) {
const isStaticImage = 'data' in image

if (!isDynamicImage && !isStaticImage) return null
const commonProps = {
alt: image.alt,
priority: image.priority,
quality: 100,
sizes:
image.sizes || buildImageSizeProp({ startSize: '100vw', lg: '490px' }),
className: clsx(
'rounded-lg px-1 pt-1',
image.objectFit === 'cover' && 'object-cover',
image.objectFit === 'contain' && 'object-contain',
image.padding && 'px-6 pt-4',
),
}

if (isStaticImage) {
return (
<Image
{...commonProps}
className={clsx(commonProps.className, 'aspect-video')}
src={image.data}
alt={commonProps.alt}
/>
)
}

const renderImage = (ImageComponent: React.ElementType) => (
return (
<div className="relative aspect-video">
<ImageComponent
{...rest}
<Image
fill
className={clsx('rounded-lg px-1 pt-1', padding && 'px-6 pt-4')}
{...commonProps}
className={clsx(commonProps.className, 'h-full w-full')}
src={image.src}
alt={commonProps.alt}
/>
</div>
)

return isDynamicImage ? renderImage(DynamicImage) : renderImage(StaticImage)
}

Card.MetaAndTags = function MetaAndTags({
Expand Down
5 changes: 1 addition & 4 deletions src/app/_components/FeaturedBlogPosts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,8 @@ export function FeaturedBlogPosts() {
text: 'Learn More',
}}
image={{
...(image || graphicsData.imageFallback.data),
alt: '',
...(image || {
...graphicsData.imageFallback,
}),
fallback: graphicsData.imageFallback,
sizes: buildImageSizeProp({
startSize: '100vw',
sm: '350px',
Expand Down
7 changes: 2 additions & 5 deletions src/app/_components/FeaturedEcosystemProjects.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,10 @@ export function FeaturedEcosystemProjects({
icon: MagnifyingGlass,
}}
image={{
...(image || graphicsData.imageFallback.data),
alt: '',
...(image || {
...graphicsData.imageFallback,
}),
fallback: graphicsData.imageFallback,
padding: true,
objectFit: 'contain',
padding: Boolean(image),
sizes: buildImageSizeProp({
startSize: '100vw',
sm: '320px',
Expand Down
7 changes: 2 additions & 5 deletions src/app/_components/FeaturedGrantGraduates.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,10 @@ export function FeaturedGrantsGraduates({
icon: BookOpen,
}}
image={{
...(image || graphicsData.imageFallback.data),
alt: '',
...(image || {
...graphicsData.imageFallback,
}),
fallback: graphicsData.imageFallback,
objectFit: 'contain',
padding: true,
padding: Boolean(image),
sizes: buildImageSizeProp({
startSize: '100vw',
sm: '175px',
Expand Down
15 changes: 7 additions & 8 deletions src/app/_components/MarkdownContent.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import Image from 'next/image'

import ReactMarkdown from 'react-markdown'
import rehypeRaw from 'rehype-raw'
import remarkGfm from 'remark-gfm'

import { graphicsData } from '@/data/graphicsData'

import { buildImageSizeProp } from '@/utils/buildImageSizeProp'

import { DynamicImage } from '@/components/DynamicImage'

type MarkdownContentProps = {
children: string
}
Expand All @@ -20,13 +18,14 @@ export function MarkdownContent({ children }: MarkdownContentProps) {
className="prose"
components={{
img: ({ src, alt }) => (
<DynamicImage
src={src || ''}
alt={alt || ''}
<Image
priority
quality={100}
src={src!}
width={800}
height={450}
fallback={graphicsData.imageFallback}
sizes={buildImageSizeProp({ startSize: '100vw', md: '660px' })}
alt={alt!}
/>
),
}}
Expand Down
54 changes: 30 additions & 24 deletions src/app/_components/PageHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import Image, { type ImageProps } from 'next/image'

import { clsx } from 'clsx'

import type { StaticImageProps } from '@/types/imageType'

import { buildImageSizeProp } from '@/utils/buildImageSizeProp'

import {
Expand All @@ -10,19 +14,17 @@ import {
DescriptionText,
type DescriptionTextType,
} from '@/components/DescriptionText'
import { DynamicImage, type DynamicImageProps } from '@/components/DynamicImage'
import { Heading } from '@/components/Heading'
import { Meta, type MetaDataType } from '@/components/Meta'
import { SectionDivider } from '@/components/SectionDivider'
import { StaticImage, type StaticImageProps } from '@/components/StaticImage'

type TitleProps = {
children: string
}

type PageHeaderProps = {
title: TitleProps['children']
image?: StaticImageProps | DynamicImageProps
image: StaticImageProps | ImageProps
isFeatured?: boolean
metaData?: MetaDataType
description?: DescriptionTextType
Expand All @@ -40,24 +42,18 @@ export function PageHeader({
return (
<header className="grid gap-4">
{isFeatured && <SectionDivider title="Featured" />}

<div className="flex flex-col gap-6 lg:flex-row">
<div className="flex flex-col gap-4 lg:w-1/2">
<div className="grid gap-6 lg:grid-cols-2">
<div className="flex flex-col gap-4">
<PageHeader.Title>{title}</PageHeader.Title>

{metaData && (
<span className="mb-2">
<Meta metaData={metaData} />
</span>
)}

{description && <DescriptionText>{description}</DescriptionText>}
{cta && <CTAButtonGroup cta={cta} />}
</div>

<div className="lg:w-1/2">
<PageHeader.Image image={image} />
</div>
{image && <PageHeader.Image image={image} />}
</div>
</header>
)
Expand All @@ -74,25 +70,35 @@ PageHeader.Title = function Title({ children }: TitleProps) {
PageHeader.Image = function PageHeaderImage({
image,
}: Pick<PageHeaderProps, 'image'>) {
if (!image) return null

const isDynamicImage = 'src' in image
const isStaticImage = 'data' in image

if (!isDynamicImage && !isStaticImage) return null

const commonProps = {
alt: image.alt,
priority: true,
quality: 100,
sizes: buildImageSizeProp({ startSize: '100vw', lg: '490px' }),
className: clsx('h-full w-full', 'rounded-lg border border-brand-100'),
className: 'rounded-lg border border-brand-100',
}

const renderImage = (ImageComponent: React.ElementType) => (
<div className={clsx('relative', 'aspect-video')}>
<ImageComponent {...image} fill={isDynamicImage} {...commonProps} />
if (isStaticImage) {
return (
<Image
{...commonProps}
className={clsx(commonProps.className, 'aspect-video')}
src={image.data}
alt={commonProps.alt}
/>
)
}

return (
<div className="relative aspect-video">
<Image
fill
{...commonProps}
className={clsx(commonProps.className, 'h-full w-full')}
src={image.src}
alt={commonProps.alt}
/>
</div>
)

return isDynamicImage ? renderImage(DynamicImage) : renderImage(StaticImage)
}
2 changes: 1 addition & 1 deletion src/app/_data/graphicsData.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { StaticImageProps } from '@/components/StaticImage'
import type { StaticImageProps } from '@/types/imageType'

import about from '@/assets/graphics/Filorg_About.png'
import digestCoverIssue1 from '@/assets/graphics/Filorg_Digest_Cover_Issue_1.webp'
Expand Down
4 changes: 2 additions & 2 deletions src/app/about/data/reportsData.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { FILECOIN_FOUNDATION_URLS } from '@/constants/siteMetadata'
import type { StaticImageProps } from '@/types/imageType'

import type { StaticImageProps } from '@/components/StaticImage'
import { FILECOIN_FOUNDATION_URLS } from '@/constants/siteMetadata'

import annualReport from '@/assets/images/022624-ff-anualreport.png'

Expand Down
23 changes: 12 additions & 11 deletions src/app/about/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,16 +88,6 @@ export default function About() {
<PageSection kicker="Insights" title="Reports">
<CardGrid cols="lgTwo" hasGridAutoRows={false}>
{reportsData.map(({ title, description, link, image }, index) => {
const imageProp = image && {
...image,
sizes: buildImageSizeProp({
startSize: '100vw',
sm: '710px',
md: '980px',
lg: '480px',
}),
}

return (
<li
key={title}
Expand All @@ -107,7 +97,18 @@ export default function About() {
as="div"
title={title}
description={description}
image={imageProp}
image={
image && {
...(image || graphicsData.imageFallback.data),
alt: '',
sizes: buildImageSizeProp({
startSize: '100vw',
sm: '710px',
md: '980px',
lg: '480px',
}),
}
}
cta={{
href: link,
text: 'View Report',
Expand Down
Loading
Loading