Skip to content

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

Description

@mekarpeles

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions