DocsComponents
Activity card
The core of the activity list: photo, category, time, age and price.
- 1Photo 4:3, 100 px high (104 px wide on phones); without a photo, the 32 px category glyph on a 12 % category tint
- 2Favourites heart in the top-left corner, before the title in tab order
- 3Niche with category glyph; date (outline badge) and time (dark badge)
- 4Title: 16 / 600, two lines max, link stretched over the card; spots left in red
- 5Meta: age label, optional rating, travel time; price on the right
- 6Container: radius 16 px, 2 px border, padding 8 px, row shadow; hover turns the border deep blue
Variants
One anatomy, optional parts. The card is a size container: narrower than 480 px it switches to the phone layout (smaller photo, title on its own line, price stacked).
States
Hover and focus are forced below. The whole card reacts, because the title link covers it: hover turns the border and the title deep blue, keyboard focus draws a 3 px ring around the card.
API reference
Props of OfferCard. Every text comes ready from the app’s translations; OfferCardSkeleton takes no content props.
| Prop | Type | Default | Description |
|---|---|---|---|
href, title, link | string, string, link component | – | The title is a link stretched over the whole card; the app injects its router link. |
category | "all" | "education" | "sport" | "art" | "events" | "places" | "gastronomy" | "health" | – | Sets data-cat: the photo tint and the placeholder take the category colour. |
categoryIconSrc, niche | string, string | – | 14 px category glyph and the niche name above the title. |
photoSrc, placeholderIconSrc | string | null, string | – | 4:3 photo; without it a 32 px category glyph on the category tint. |
mediaAction | ReactNode | – | Slot on the photo for the favourites heart; empty = no heart. |
day, time | string | – | Date badge (outline) and time badge (dark). |
spots, spotsTone | string, "warn" | "none" | "warn" | Ready text with the number of spots; warn is red. |
age | ReactNode | – | An AgeLabel: age icon 14 px + label 13 / 600. |
rating | { value, count? } | – | Optional star rating with the number of reviews. |
travel | drive (car, walk?) | online | home | – | Travel time or the form of classes; hidden below 768 px, walking time hidden in the phone layout. |
priceUnit, price | string, string | – | Unit before the amount (“from”) and the amount or “Free”. |
soldOut | boolean | false | No spots left: the photo turns greyscale at 70 % opacity. |
Accessibility
- The card is an article; its title is the only link, stretched over the card, so a screen reader hears one link per card, named by the title.
- The favourites heart sits before the title in the DOM, so Tab reaches it first; it has its own name (“Save to favourites: …”) and a 44 px target.
- Travel icons are decorative; “By car” / “On foot” are read only by screen readers.
- Loading: the skeleton is hidden from screen readers; the list container announces the state (role="status", aria-busy).
- Contrast on the white card: title 20.2:1 (hover 8.4:1), meta 7.6:1, spots left 6.5:1, time badge 20.2:1. Focus ring: 3 px in the ring token, 4.0:1 against white.
- The 2 px resting border is only a soft edge (1.1:1 against the page); the card is recognised by the white surface and the row shadow, and hover raises the border to 7.6:1.