import Elementary import Persistence /// A listing in a card grid: its cover, title, price, grade chip, and — depending on the ``Context`` — the shop selling it. struct ListingCard: HTML { // MARK: Properties /// Where the card is shown. let context: Context /// The listing the card shows. let listing: Listing // MARK: Initializers /// Creates a listing card. /// - Parameters: /// - listing: the listing the card shows. /// - context: where the card is shown; a browsing row by default. init( _ listing: Listing, context: Context = .browse ) { self.context = context self.listing = listing } // MARK: Computed var body: some HTML { article(.class("listing-card")) { // Saving is a gated action: signed out, it leads to the sign-in screen. a( .class("listing-card__save"), .href(.Route.signIn(returningTo: listing.path)), .custom( name: "aria-label", value: "Save \(listing.title) to watchlist" ) ) { Icon(.bookmark, size: 18) } a( .class("listing-card__cover"), .href(listing.path), .custom( name: "tabindex", value: "-1" ), .custom( name: "aria-hidden", value: "true" ) ) { ListingImage(listing) } div { h3(.class("type-card-title")) { a( .class("listing-card__title"), .href(listing.path) ) { listing.title } } p(.class("listing-card__meta")) { listing.summary } } div(.class("listing-card__row")) { span(.class("type-price-card")) { listing.priceCents.euros } Chip( listing.chip.label, tone: listing.chip.tone, isCertified: listing.chip.isCertified ) } if context != .shop { a( .class("listing-card__shop"), .href(listing.shop.path) ) { context == .search ? "\(listing.shop.name) · \(listing.shop.country) · ship \(listing.shippingCents.euros)" : listing.shop.name } } } } } // MARK: - Enumerations extension ListingCard { /// Where a listing card is shown. enum Context: Sendable { /// A browsing row: the shop is named. case browse /// Search results: the shop is named with its country and shipping cost. case search /// The shop's own screen: the shop goes unnamed. case shop } }