No cover available
+ )} +{book.title}
+{authors}
+ {book.firstPublishYear !== null &&First published: {book.firstPublishYear}
} + {book.subjects.length > 0 && ( +-
+ {book.subjects.map((subject) => (
+
- {subject} + ))} +
diff --git a/src/components/BookCard.css b/src/components/BookCard.css
new file mode 100644
index 0000000..a5aad97
--- /dev/null
+++ b/src/components/BookCard.css
@@ -0,0 +1,78 @@
+.book-card {
+ display: grid;
+ grid-template-columns: minmax(8rem, 12rem) 1fr;
+ gap: 1.5rem;
+ overflow: hidden;
+ border: 1px solid #d5dde5;
+ border-radius: 0.75rem;
+ background-color: #ffffff;
+ box-shadow: 0 0.25rem 0.75rem rgb(44 62 80 / 12%);
+}
+
+.book-card-cover {
+ display: grid;
+ min-height: 12rem;
+ place-items: center;
+ background-color: #edf2f7;
+ color: #52606d;
+ text-align: center;
+}
+
+.book-card-cover img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+}
+
+.book-card-cover p {
+ margin: 1rem;
+}
+
+.book-card-content {
+ padding: 1.25rem 1.25rem 1.25rem 0;
+}
+
+.book-card-content h2 {
+ margin: 0;
+ color: #243b53;
+}
+
+.book-card-content p {
+ margin: 0.5rem 0 0;
+ color: #52606d;
+}
+
+.book-card-authors {
+ font-weight: 600;
+}
+
+.book-card-subjects {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.5rem;
+ margin: 1rem 0 0;
+ padding: 0;
+ list-style: none;
+}
+
+.book-card-subjects li {
+ border-radius: 999px;
+ background-color: #d9e2ec;
+ color: #243b53;
+ padding: 0.25rem 0.625rem;
+ font-size: 0.875rem;
+}
+
+@media (max-width: 32rem) {
+ .book-card {
+ grid-template-columns: 1fr;
+ }
+
+ .book-card-cover {
+ min-height: 16rem;
+ }
+
+ .book-card-content {
+ padding: 0 1.25rem 1.25rem;
+ }
+}
diff --git a/src/components/BookCard.test.tsx b/src/components/BookCard.test.tsx
new file mode 100644
index 0000000..4e74de9
--- /dev/null
+++ b/src/components/BookCard.test.tsx
@@ -0,0 +1,44 @@
+import { render, screen } from "@testing-library/react";
+import { describe, expect, it } from "vitest";
+import type { Book } from "../types";
+import { BookCard } from "./BookCard";
+
+const fullBook: Book = {
+ key: "/works/OL1",
+ title: "A Wizard of Earthsea",
+ authors: ["Ursula K. Le Guin", "Another Author"],
+ firstPublishYear: 1968,
+ coverId: 123,
+ subjects: ["Fantasy", "Magic"],
+};
+
+const minimalBook: Book = {
+ key: "/works/OL2",
+ title: "Untitled Book",
+ authors: [],
+ firstPublishYear: null,
+ coverId: null,
+ subjects: [],
+};
+
+describe("BookCard", () => {
+ it("renders a complete book", () => {
+ const { container } = render( No cover available {authors} First published: {book.firstPublishYear}
+ ) : (
+
{book.title}
+
+ {book.subjects.map((subject) => (
+
+ )}
+
+ + First published: + 1968 +
++ No cover available +
+