import SwiftUI struct BookCoverCard: View { let book: BookRemote let imageCache: ImageCacheProtocol var body: some View { VStack(spacing: 6) { RemoteImageView(url: book.coverImageUrl, imageCache: imageCache) .frame(width: 98, height: 145) .clipShape(RoundedRectangle(cornerRadius: 10, style: .continuous)) .overlay { RoundedRectangle(cornerRadius: 10) .stroke(Color.black.opacity(0.08), lineWidth: 1) } .shadow(color: .black.opacity(0.16), radius: 6, y: 4) Text(book.title) .font(.caption) .lineLimit(1) .foregroundStyle(.primary) } .accessibilityElement(children: .combine) .accessibilityLabel("\(book.title), \(book.authors.joined(separator: ", "))") } } private struct RemoteImageView: View { let url: URL? let imageCache: ImageCacheProtocol @State private var image: UIImage? var body: some View { ZStack { RoundedRectangle(cornerRadius: 10) .fill(LinearGradient(colors: [Color.gray.opacity(0.22), Color.gray.opacity(0.35)], startPoint: .top, endPoint: .bottom)) if let image { Image(uiImage: image) .resizable() .scaledToFill() } else { Image(systemName: "book.closed") .font(.title3) .foregroundStyle(Color.black.opacity(0.35)) } } .task(id: url) { guard let url else { return } do { image = try await imageCache.image(for: url) } catch { image = nil } } } }