Загрузка данных


Да, это очень сильно меняет дело! Теперь у нас есть точные CSS-классы и готовая верстка. Чтобы приложение выглядело в точности как задумано (со всеми стилями, галочками и цветами), нам нужно интегрировать эти классы в наши React-компоненты.
Кроме того, в твоем CSS есть классы состояний (например, .done для прочитанной книги и .checked для галочки), которые мы будем динамически добавлять через JavaScript.
Стили из index.css можешь целиком скопировать в файл src/index.css (или App.css), чтобы они применились ко всему проекту.
Вот как теперь должны выглядеть твои компоненты с правильной версткой:
1. src/App.jsx
Вставляем шапку (бренд "Shelf") и передаем состояние вниз.
import { useState } from 'react'
import ShelfScreen from './pages/ShelfScreen/ShelfScreen'
import './index.css' // Подключаем твои стили

function App() {
  const [books, setBooks] = useState([
    { id: 1, title: 'Клара и Солнце', author: 'Кадзуо Исигуро', read: true }
  ])
  const [showOnlyUnread, setShowOnlyUnread] = useState(false)

  const handleAddBook = (title) => {
    const newBook = {
      id: Date.now(),
      title,
      author: 'Неизвестный автор',
      read: false
    }
    setBooks(prev => [...prev, newBook])
  }

  const handleToggleRead = (id) => {
    setBooks(prev => prev.map(book => 
      book.id === id ? { ...book, read: !book.read } : book
    ))
  }

  const handleDeleteBook = (id) => {
    setBooks(prev => prev.filter(book => book.id !== id))
  }

  return (
    <div className="app">
      <div className="app-header">
        <div className="brand">
          <div className="brand-mark">S</div>
          <div className="brand-name">Shelf</div>
        </div>
      </div>
      
      <ShelfScreen 
        books={books}
        showOnlyUnread={showOnlyUnread}
        setShowOnlyUnread={setShowOnlyUnread}
        onAddBook={handleAddBook}
        onToggleRead={handleToggleRead}
        onDeleteBook={handleDeleteBook}
      />
    </div>
  )
}

export default App

2. src/pages/ShelfScreen/ShelfScreen.jsx
Оборачиваем все в <section className="screen active">.
import BookForm from '../../components/BookForm/BookForm'
import BookList from '../../components/BookList/BookList'

export default function ShelfScreen({ 
  books, 
  showOnlyUnread, 
  setShowOnlyUnread, 
  onAddBook, 
  onToggleRead, 
  onDeleteBook 
}) {
  const filteredBooks = showOnlyUnread 
    ? books.filter(book => !book.read)
    : books;

  return (
    <section className="screen active" id="screen-shelf">
      <p className="greeting">Добрый вечер</p>
      
      <BookForm onAdd={onAddBook} />
      
      <div className="list-toolbar">
        <span className="toolbar-title">Книги</span>
        <div className="filter-chip">
          <input 
            type="checkbox" 
            id="filterCheckbox" 
            checked={showOnlyUnread}
            onChange={() => setShowOnlyUnread(prev => !prev)}
          />
          <label htmlFor="filterCheckbox">
            <span className="dot" />
            Только непрочитанные
          </label>
        </div>
      </div>

      <BookList 
        books={filteredBooks} 
        onToggleRead={onToggleRead}
        onDeleteBook={onDeleteBook}
      />
    </section>
  )
}

3. src/components/BookForm/BookForm.jsx
Заменим div className="add-book-row" на form, чтобы книга добавлялась не только по клику, но и по нажатию Enter.
import { useState } from 'react'

export default function BookForm({ onAdd }) {
  const [title, setTitle] = useState('')

  const handleSubmit = (e) => {
    e.preventDefault()
    const trimmedTitle = title.trim()
    
    if (trimmedTitle) {
      onAdd(trimmedTitle)
      setTitle('') 
    }
  }

  return (
    <form className="add-book-row" onSubmit={handleSubmit}>
      <input 
        className="input" 
        placeholder="Название книги..." 
        value={title}
        onChange={(e) => setTitle(e.target.value)}
      />
      <button type="submit" className="btn">
        Добавить на полку
      </button>
    </form>
  )
}

4. src/components/BookList/BookList.jsx
Рендерит список. Если книг нет, показывает стилизованное сообщение.
import BookItem from '../BookItem/BookItem'

export default function BookList({ books, onToggleRead, onDeleteBook }) {
  if (books.length === 0) {
    return <div className="empty-note">Полка пуста</div>
  }

  return (
    <div className="book-list">
      {books.map(book => (
        <BookItem 
          key={book.id} 
          book={book} 
          onToggle={onToggleRead}
          onDelete={onDeleteBook}
        />
      ))}
    </div>
  )
}

5. src/components/BookItem/BookItem.jsx
Здесь добавляем динамические классы: если книга прочитана, к названию добавляется класс done, а к кнопке-галочке — класс checked.
export default function BookItem({ book, onToggle, onDelete }) {
  // Цвета из твоего дизайна
  const colors = ['#4f6b52', '#8a3a3a', '#c9a227', '#6f6353', '#2c231c']
  const coverColor = colors[book.id % colors.length]
  
  // Берем первую букву названия для обложки
  const firstLetter = book.title ? book.title.charAt(0).toUpperCase() : '?'

  return (
    <div className="book-row">
      <div className="book-cover" style={{ background: coverColor }}>
        {firstLetter}
      </div>
      
      <div className="book-info">
        {/* Если книга прочитана, добавляем класс 'done' */}
        <p className={`book-title ${book.read ? 'done' : ''}`}>
          {book.title}
        </p>
        <div className="book-author">{book.author}</div>
      </div>
      
      {/* Если книга прочитана, добавляем класс 'checked' */}
      <div 
        className={`read-check ${book.read ? 'checked' : ''}`} 
        onClick={() => onToggle(book.id)}
      >
        <span className="check-circle">✓</span>
        <span className="read-label">Прочитано</span>
      </div>
      
      <button
        className="delete-btn"
        title="Убрать с полки"
        onClick={() => onDelete(book.id)}
      >
        ✕
      </button>
    </div>
  )
}