diff --git a/frontend/src/components/ArtworkCard.css b/frontend/src/components/ArtworkCard.css new file mode 100644 index 0000000..737ab3f --- /dev/null +++ b/frontend/src/components/ArtworkCard.css @@ -0,0 +1,41 @@ +.artwork-card { + min-width: 0; + padding: 16px; + border: 1px solid #dedede; + border-radius: 4px; + background: #fff; + color: #171717; + text-align: left; +} + +.artwork-card__image, +.artwork-card__placeholder { + display: block; + width: 100%; + aspect-ratio: 4 / 5; +} + +.artwork-card__image { + object-fit: contain; + background: #f5f4f1; +} + +.artwork-card__placeholder { + display: grid; + place-items: center; + background: #f5f4f1; + color: #595959; +} + +.artwork-card__title { + margin: 16px 0 8px; + font-size: 1.5rem; + line-height: 1.2; + overflow-wrap: anywhere; +} + +.artwork-card__artist { + margin: 0; + color: #595959; + overflow-wrap: anywhere; +} \ No newline at end of file diff --git a/frontend/src/components/ArtworkCard.tsx b/frontend/src/components/ArtworkCard.tsx new file mode 100644 index 0000000..897e1c8 --- /dev/null +++ b/frontend/src/components/ArtworkCard.tsx @@ -0,0 +1,52 @@ +import { useState } from 'react' +import type { Artwork } from '../types/Artwork' +import './ArtworkCard.css' + +type ArtworkCardProps = { + artwork: Artwork +} + +function ArtworkImage({ src, alt }: { src: string; alt: string }) { + const [hasError, setHasError] = useState(false) + + if (hasError) { + return ( +
+ Image unavailable +
+ ) + } + + return ( + {alt} setHasError(true)} + /> + ) +} + +export default function ArtworkCard({ artwork }: ArtworkCardProps) { + const artist = artwork.artist?.trim() || 'Unknown artist' + + return ( +
+ {artwork.imageUrl ? ( + + ) : ( +
+ Image unavailable +
+ )} + +

{artwork.title}

+

{artist}

+
+ ) +} \ No newline at end of file diff --git a/frontend/src/components/ArtworkGrid.css b/frontend/src/components/ArtworkGrid.css new file mode 100644 index 0000000..904c56e --- /dev/null +++ b/frontend/src/components/ArtworkGrid.css @@ -0,0 +1,19 @@ +.artwork-grid { + display: grid; + grid-template-columns: minmax(0, 1fr); + align-items: start; + gap: 20px; + margin: 0; + padding: 0; + list-style: none; +} + +.artwork-grid > li { + min-width: 0; +} + +@media (min-width: 1024px) { + .artwork-grid { + grid-template-columns: repeat(4, minmax(0, 1fr)); + } +} \ No newline at end of file diff --git a/frontend/src/components/ArtworkGrid.tsx b/frontend/src/components/ArtworkGrid.tsx new file mode 100644 index 0000000..d12f73a --- /dev/null +++ b/frontend/src/components/ArtworkGrid.tsx @@ -0,0 +1,23 @@ +import type { Artwork } from '../types/Artwork' +import ArtworkCard from './ArtworkCard' +import './ArtworkGrid.css' + +type ArtworkGridProps = { + artworks: Artwork[] +} + +export default function ArtworkGrid({ artworks }: ArtworkGridProps) { + if (artworks.length === 0) { + return

No artworks to display.

+ } + + return ( + + ) +} \ No newline at end of file diff --git a/frontend/src/types/Artwork.ts b/frontend/src/types/Artwork.ts new file mode 100644 index 0000000..f44a2eb --- /dev/null +++ b/frontend/src/types/Artwork.ts @@ -0,0 +1,8 @@ +export type Artwork = { + id: string | number + title: string + artist: string | null + imageUrl: string | null + imageAlt?: string | null + date?: string | null +}