ArchiveLabs / ArchiveLabs/openlibrary-components

feat: Netflix-style expandable card — inline detail panel on result card expand

Open
#46 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
JavaScript
Stars
0
Forks
0
PR merge metrics
No merged PRs in 30d

Description

## Concept

Netflix shows a grid of title cards. Hovering or clicking a card reveals an inline expanded panel below the card row — a larger hero image, playback controls, genre tags, and a description — without navigating away. A styled **⌄ chevron** button in the bottom-right of the expanded panel collapses it back.

Reference screenshot (Netflix, searched "lord of the rings"):

> *User-attached screenshot shows: normal thumbnail cards in a grid; one card (The Green Knight) is expanded — it floats taller and wider, breaking out of the grid row, with a still image, ▶ / + / 👍 action buttons, a ⌄ collapse chevron, rating badge (R), runtime (2h 16m), quality (HD), and descriptive tags "Violent • Epic • Visually Striking".*

---

## Proposed behaviour for Open Library

### Where it applies
Both surfaces currently show book cards:

| Surface | Component | Card element |
|---|---|---|
| Autocomplete panel (droppable) | `ol-search-bar` — `_renderResults()` | `.ac-row` |
| Full search results page | `ol-search-page` → `ol-book-card` | `` |

The feature is most impactful on **`ol-book-card`** (full results page) since those cards are already larger. The autocomplete rows are space-constrained and may only need a lighter treatment (see open questions).

### Interaction model
1. Each card has a small **⌄ expand chevron** button in its bottom-right corner (visible on hover, always visible on touch).
2. Clicking the chevron expands that card **in place** — the card grows vertically to reveal additional content; surrounding cards reflow below it.
3. Only one card is expanded at a time; expanding another collapses the current one.
4. The same chevron (now ⌃) collapses back to the compact view.
5. Keyboard: `Enter`/`Space` on the chevron toggles; `Escape` collapses.

### Expanded content to show
Fields already available on the `work` object returned by the OL search API:

- **Larger cover image** (use `-L` size suffix instead of `-M`)
- **First sentence / description** (`w.first_sentence` or `w.description` — may need an additional `/works/OLxxxW.json` fetch if not in search results)
- **Subjects** (`w.subject` — first 4–5 tags)
- **Series** (`w.series?.[0]`)
- **Edition count** (`w.edition_count`)
- **OL work page link** (full `/works/OLxxxW` URL)
- **Action buttons**: "Read now" (if `ebook_access >= borrowable`), "Want to Read" / reading-log CTA, "More details →"

### What may require an extra fetch
The OL search API does not return `description` or `first_sentence` for works. A lightweight fetch to `/works/OLxxxW.json` on expand (not on card render) could populate these. The fetch should be:
- Triggered only on first expand (cache the result on the element)
- Abortable if the card is collapsed before the response arrives
- Shown as a skeleton/spinner state while loading

---

## Open questions

1. **Autocomplete rows** — should `.ac-row` in the droppable panel also get an expand chevron, or is the panel too space-constrained? A simpler option: clicking the row body navigates to the work page; the chevron is omitted in the panel.
2. **Extra fetch** — is `first_sentence` / `description` worth the extra round-trip? Could use subjects + edition count as the expanded content without any additional request.
3. **Animation** — smooth height transition (`max-height` CSS transition) vs. instant reflow. CSS transition is preferred for perceived quality but must not janky-scroll on mobile.
4. **Grid vs. list layout** — `ol-search-page` currently renders cards in a single column (`flex-direction: column`). The Netflix effect (card expands across multiple columns) requires a CSS grid layout. Is a grid refactor in scope here, or should the expand just grow vertically in the single column?

---

## Implementation sketch

### `ol-book-card` changes
- Add `_expanded = false` reactive state property
- Add chevron button (`▾` / `▴`) wired to `_toggleExpand()`
- In `_toggleExpand()`: fire a custom `ol-card-expand` event (bubbles, composed) so the parent page can collapse any previously open card
- Render expanded content block conditionally; trigger fetch on first expand

### `ol-search-page` changes
- Listen for `ol-card-expand` and set `_expandedWork` to the work key; re-render (Lit handles diffing)
- Pass `.expanded=${w.key === this._expandedWork}` to each ``

### Pure-logic additions (`filters.js` or new `utils/works.js`)
- `buildWorkUrl(work)` — already exists as `bestEdition`; may need a `workPageUrl` variant
- `isReadable(work)` — check `ebook_access >= borrowable` (already used in `bestEdition`)

---

## Acceptance criteria
- [ ] Each `ol-book-card` has a ▾ chevron; clicking it expands the card with additional metadata
- [ ] Only one card expanded at a time
- [ ] Expanded state shows cover (larger), subjects, edition count, action buttons
- [ ] If description requires an extra fetch: loading skeleton shown; fetch aborted on collapse
- [ ] Keyboard accessible (Enter/Space to toggle, Escape to collapse)
- [ ] No layout shift on cards that are not expanded
- [ ] Vitest contract test: `ol-book-card` declares `_expanded` reactive property and emits `ol-card-expand`

Contributor guide

Open the contributing guide

Research direction

Start by reading the ol-book-card, ol-search-page, and ol-search-bar _renderResults() implementations, then inspect the existing bestEdition logic and Vitest contract-test setup. Resolve the open questions about autocomplete coverage, the extra work fetch, animation, and grid layout before implementing the expanded state, single-card coordination, keyboard behavior, and metadata actions. Done means the acceptance criteria pass, including the reactive-property and event contract test.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
frontend, web-dev
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.