ArchiveLabs / ArchiveLabs/openlibrary-components

feat: redesign Sort dropdown with Sort By / Order sections and Reading Log submenu

Open
#45 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

## Background

The current Sort/Relevance facet dropdown (`ol-facet-drop` `_renderSort()`) renders a flat list of radio buttons mapping directly to Open Library Solr sort values:

\`\`\`js
// frontend/src/utils/filters.js
export const SORT_OPTIONS = [
{ value: '', label: 'Relevance' },
{ value: 'new', label: 'Newest first' },
{ value: 'old', label: 'Oldest first' },
{ value: 'rating desc', label: 'Top rated' },
{ value: 'readinglog desc',label: 'Most read' },
{ value: 'title', label: 'Title A–Z' },
];
\`\`\`

The flat list conflates two orthogonal decisions — *what field to sort on* and *which direction* — and hides "Reading Log" as a peer of "Relevance" with no indication that sub-options exist.

## Proposed redesign

### Part 1 — Sort by / Order two-section layout (inspired by GitHub's sort UX)

Split the dropdown into two named sections:

**Sort by** (checkbox-style, single selection — not radio so the label can be styled more flexibly):
- Relevance *(no Order section shown when selected)*
- Date published → Order: Newest / Oldest
- Rating → Order: Highest / Lowest
- Reading log → Order: Most read / Least read *(see Part 2)*
- Title → Order: A–Z / Z–A

**Order** (only visible when a field that has a direction is selected):
Shows the two direction options for the chosen sort field, e.g. "Newest" / "Oldest" for Date.

This keeps the Solr `sort` param values (`new`, `old`, `rating desc`, `readinglog desc`, `title`) but derives them from two independent UI selections rather than encoding both in one flat list.

### Part 2 — Reading Log submenu (right-chevron trigger, inspired by GitHub's Reactions submenu)

"Reading Log" in the Sort by section should behave like GitHub's "Reactions" item: a right-facing chevron (›) indicates a submenu. Clicking/hovering opens a nested panel with:

- Want to Read
- Currently Reading
- Already Read

Each maps to a different OL reading-log sort bucket. The selected sublabel should appear in the facet button's chip text (e.g. "Reading Log: Want to Read").

This requires research into which Solr/OL API parameters map to each reading-log state. The current value `readinglog desc` is the aggregate; individual states may need different params.

## Implementation notes

### Data shape
The `sort` field in `EMPTY_FILTERS` is currently a single string. Implementing Order as a separate axis may require adding a `sortDir` field, or keeping a single derived string (simpler — avoids ripple changes). Worth deciding before coding.

### Pure-logic first (per AGENTS.md)
All new option constants and any `buildChips` / `buildSearchParams` changes belong in `filters.js` and must be covered by Vitest before touching the component.

### Component changes
- `ol-facet-drop.js` — `_renderSort()` becomes a two-panel layout; submenu state (open/closed) is local to the component
- `filters.js` — possibly new `SORT_FIELDS` and per-field direction options; update `getSortLabel`, `buildChips`, `buildSearchParams`
- `ol-search-bar.js` — minimal; the facet button label comes from `_facetLabel('sort')` which calls `getSortLabel`

### Submenu interaction model
Two options to evaluate:
1. **Click to toggle** — clicking the Reading Log row expands an inline sub-list (no separate panel); simpler to implement and accessible
2. **Right-panel submenu** — clicking opens a second panel sliding in from the right (matches GitHub's pattern but more complex)

Option 1 is recommended unless the design specifically needs the slide-in feel.

### OL API research needed
- Confirm Solr params for per-reading-log-state sorts (want-to-read / currently-reading / already-read)
- Check whether the OL search API exposes these as distinct `sort=` values or requires a separate filter param
- Update `backend/main.py` to proxy the new param if needed

## Acceptance criteria
- [ ] Sort by section shows field names; Order section shows directions for that field
- [ ] Selecting "Relevance" hides the Order section entirely
- [ ] Reading Log row shows a right chevron and expands to show the three sub-states
- [ ] Facet button chip text reflects the full selection (field + direction, or field + sub-state)
- [ ] `filters.js` pure-logic changes covered by Vitest before component changes
- [ ] Existing sort Playwright/Vitest tests updated; no regressions

Contributor guide

Open the contributing guide

Research direction

Start with _renderSort() in frontend/src/components/ol-facet-drop.js and the sort constants and helpers in frontend/src/utils/filters.js. Run the existing Vitest and Playwright sort tests, then inspect backend/main.py and the Open Library search API to determine whether reading-log states have distinct sort parameters. Done means the two-section sort UI, Reading Log submenu, labels, parameter handling, and updated tests satisfy every acceptance criterion without regressions.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, playwright
Domain
api, frontend, testing
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.