diff --git a/src/components/BookCard.jsx b/src/components/BookCard.jsx new file mode 100644 index 0000000..9d125e7 --- /dev/null +++ b/src/components/BookCard.jsx @@ -0,0 +1,52 @@ +import styles from './BookCard.module.css'; + +const BookCard = ({ book, onEdit, onDelete }) => { + const getStatusClass = (status) => { + switch (status) { + case 'pending': + return styles['book-card__status--pending']; + case 'in progress': + return styles['book-card__status--in-progress']; + case 'read': + return styles['book-card__status--read']; + default: + return styles['book-card__status--pending']; + } + }; + + return ( +
+
+

{book.title}

+ {book.year} +
+ +

{book.author}

+ +
+ + {book.status} + +
+ +
+ + +
+
+ ); +}; + +export default BookCard; diff --git a/src/components/BookCard.module.css b/src/components/BookCard.module.css new file mode 100644 index 0000000..da8ebdc --- /dev/null +++ b/src/components/BookCard.module.css @@ -0,0 +1,117 @@ +.book-card { + background: white; + border: 1px solid #e9ecef; + border-radius: 4px; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05); + padding: 1rem; + transition: box-shadow 0.2s; +} + +.book-card:hover { + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); +} + +.book-card__header { + display: flex; + justify-content: space-between; + align-items: flex-start; + margin-bottom: 0.5rem; + gap: 1rem; +} + +.book-card__title { + margin: 0; + font-size: 1.125rem; + font-weight: 700; + color: #212529; + line-height: 1.3; + flex: 1; +} + +.book-card__year { + background-color: #e9ecef; + color: #6c757d; + padding: 0.25rem 0.5rem; + border-radius: 3px; + font-size: 0.75rem; + font-weight: 500; + white-space: nowrap; +} + +.book-card__author { + margin: 0 0 1rem 0; + color: #6c757d; + font-size: 0.875rem; +} + +.book-card__status-container { + margin-bottom: 1rem; + padding-bottom: 1rem; + border-bottom: 1px solid #e9ecef; +} + +.book-card__status { + display: inline-block; + padding: 0.25rem 0.5rem; + border-radius: 3px; + font-size: 0.75rem; + font-weight: 500; + text-transform: lowercase; +} + +.book-card__status--pending { + background-color: #fff5d9; + color: #ec8a4d; +} + +.book-card__status--in-progress { + background-color: #ddeffd; + color: #2e5eab; +} + +.book-card__status--read { + background-color: #d4edda; + color: #42a646; +} + +.book-card__actions { + display: flex; + gap: 0.5rem; +} + +.book-card__button { + flex: 1; + padding: 0.5rem 1rem; + border-radius: 3px; + font-size: 0.875rem; + cursor: pointer; + transition: all 0.2s; + border: 1px solid; + font-weight: 400; +} + +.book-card__button--delete { + background-color: #fde7e9; + color: #ac3031; + border-color: #fde7e9; +} + +.book-card__button--edit { + background-color: #f8f9fa; + color: #495057; + border-color: #ced4da; +} + +@media (min-width: 768px) { + .book-card { + padding: 1.5rem; + } + + .book-card__title { + font-size: 1.25rem; + } + + .book-card__author { + font-size: 1rem; + } +} diff --git a/src/components/BookForm.jsx b/src/components/BookForm.jsx new file mode 100644 index 0000000..a0f33fc --- /dev/null +++ b/src/components/BookForm.jsx @@ -0,0 +1,121 @@ +import { useState, useEffect } from 'react'; +import styles from './BookForm.module.css'; + +const BookForm = ({ book, onSubmit, onCancel }) => { + const [formData, setFormData] = useState({ + title: '', + author: '', + year: new Date().getFullYear(), + status: 'pending', + }); + + useEffect(() => { + if (book) { + setFormData({ + title: book.title, + author: book.author, + year: book.year, + status: book.status, + }); + } + }, [book]); + + const handleSubmit = (e) => { + e.preventDefault(); + if (formData.title.trim() && formData.author.trim()) { + onSubmit(formData); + } + }; + + const handleChange = (e) => { + const { name, value } = e.target; + setFormData((prev) => ({ + ...prev, + [name]: value, + })); + }; + + return ( +
+

+ {book ? 'Edit Book' : 'Add New Book'} +

+ +
+
+ + +
+ +
+ + +
+ +
+
+ + +
+ +
+ + +
+
+ + +
+
+ ); +}; + +export default BookForm; diff --git a/src/components/BookForm.module.css b/src/components/BookForm.module.css new file mode 100644 index 0000000..b5f9c85 --- /dev/null +++ b/src/components/BookForm.module.css @@ -0,0 +1,101 @@ +.book-form { + background: white; + margin: 1rem; + padding: 1.5rem; + border: 1px solid #e9ecef; + border-radius: 4px; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05); +} + +.book-form__title { + margin: 0 0 1.5rem 0; + font-size: 1.25rem; + color: #212529; + font-weight: 600; +} + +.book-form__form { + display: flex; + flex-direction: column; + gap: 1rem; +} + +.book-form__group { + display: flex; + flex-direction: column; +} + +.book-form__row { + display: grid; + grid-template-columns: 1fr; + gap: 1rem; +} + +.book-form__label { + margin-bottom: 0.5rem; + font-weight: 500; + color: #212529; + font-size: 0.875rem; +} + +.book-form__input, +.book-form__select { + padding: 0.5rem 0.75rem; + border: 1px solid #ced4da; + border-radius: 4px; + font-size: 1rem; + transition: + border-color 0.2s, + box-shadow 0.2s; + background-color: white; +} + +.book-form__input:focus, +.book-form__select:focus { + outline: none; + border-color: #80bdff; + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.book-form__input::placeholder { + color: #6c757d; +} + +.book-form__select { + cursor: pointer; +} + +.book-form__button { + background-color: #42a646; + color: white; + border: none; + padding: 0.75rem 1rem; + border-radius: 4px; + font-size: 0.9rem; + font-weight: 500; + cursor: pointer; + transition: background-color 0.2s; + margin-top: 0.5rem; + align-self: flex-end; +} + +@media (min-width: 768px) { + .book-form { + margin: 1rem auto; + max-width: 600px; + padding: 2rem; + } + + .book-form__title { + font-size: 1.5rem; + } + + .book-form__row { + grid-template-columns: 1fr 1fr; + } + + .book-form__button { + padding: 0.75rem 1.5rem; + font-size: 1rem; + } +} diff --git a/src/components/BookList.jsx b/src/components/BookList.jsx new file mode 100644 index 0000000..7775dde --- /dev/null +++ b/src/components/BookList.jsx @@ -0,0 +1,19 @@ +import BookCard from './BookCard'; +import styles from './BookList.module.css'; + +function BookList({ books, onEdit, onDelete }) { + return ( +
+ {books.map((book) => ( + + ))} +
+ ); +} + +export default BookList; diff --git a/src/components/BookList.module.css b/src/components/BookList.module.css new file mode 100644 index 0000000..d274d69 --- /dev/null +++ b/src/components/BookList.module.css @@ -0,0 +1,7 @@ +.book-list { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); + gap: 1rem; + padding: 1rem; + width: 100%; +}