ArchiveLabs / ArchiveLabs/openlibrary-components
feat: redesign Sort dropdown with Sort By / Order sections and Reading Log submenu
- 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
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