feat: Consolidate sidebar buy options into unified Buy button dropdown - #13113
Conversation
b59e86d to
a36b303
Compare
There was a problem hiding this comment.
Pull request overview
Consolidates “Buy” affordances into the unified Buy popover on edition pages by removing the legacy sidebar vendor panels and restyling affiliate link options for a flatter, full-row-clickable dropdown list. This aligns the edition page CTA area with the newer popover-based UI patterns.
Changes:
- Removes the legacy mobile/desktop vendor panels from the edition page and renders affiliate links inside an
<ol-popover>Buy dropdown. - Refactors affiliate links markup (loading indicator + store list) to use
<div>containers and a flat list layout with prices aligned right. - Adds CSS for the Buy popover (trigger + content) and makes the left “editionCover” column sticky on desktop.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| static/css/components/work.css | Makes the edition cover/tool column sticky on desktop for persistent CTAs. |
| static/css/components/read-panel.css | Adds styling for the Buy popover dropdown and custom Buy button layout. |
| openlibrary/templates/type/edition/view.html | Removes the legacy mobile vendor panel from the edition page layout. |
| openlibrary/macros/LoanStatus.html | Removes the post injection point previously used for rendering the lists widget within LoanStatus. |
| openlibrary/macros/databarWork.html | Adds the Buy <ol-popover> and relocates the lists widget rendering after the CTA area. |
| openlibrary/macros/AffiliateLinksLoadingIndicator.html | Switches the async loading wrapper from <span> to <div>. |
| openlibrary/macros/AffiliateLinks.html.jinja | Refactors affiliate link items into full-row clickable blocks with name/price alignment and updated disclaimer styling hook. |
| openlibrary/i18n/messages.pot | Updates extracted string references and reintroduces “Buy this book” for the new popover aria-label. |
| docker/Dockerfile.olbase | Touches node_modules before make to avoid rebuild churn during image build. |
| bundlesize.config.json | Adjusts bundlesize max for admin CSS bundle. |
| $# Buy button is primary (blue) only when no digital access and a WorldCat URL exists | ||
| $ availability = (page.availability or {}) if hasattr(page, 'availability') else {} | ||
| $ _has_digital = bool(page.get('ocaid') or availability.get('is_readable') or availability.get('status') == 'open' or availability.get('is_lendable') or availability.get('is_previewable')) | ||
| $ buy_is_primary = editions_page and not _has_digital and bool(worldcat_url) |
|
|
||
| $if editions_page: | ||
| <ol-popover class="buy-popover" aria-label="$_('Buy this book')"> | ||
| <button slot="trigger" type="button" class="cta-btn cta-btn--w-icon cta-btn--buy"> |
| .cta-btn--buy { | ||
| position: relative; | ||
| background-color: var(--grey-464646); | ||
| color: var(--white); | ||
| margin-top: 0; | ||
| height: 37px; | ||
| padding: 0 var(--spacing-inset-sm); | ||
| display: flex; | ||
| align-items: center; | ||
| justify-content: center; | ||
| } | ||
|
|
||
| .cta-btn--buy:hover { | ||
| background-color: var(--dark-grey); | ||
| } |
9d3363e to
441dd70
Compare
|
PR #13113 — Rebase + verification (Ada, on behalf of Mek) Rebased this branch onto current Rebase
Two commits dropped, both verified lossless: the two CORRECTNESS🔴 BLOCKING — every edition page 500s.
Isolated to this single line: neutralizing just that expression makes Suggested fix — delete lines 5-8 entirely (4 lines, zero rendered-output change). 🔴 BLOCKING — the WorldCat link is removed from book pages. The PR description says this "consolidates the sidebar WorldCat/library locate links and purchase/affiliate options into the unified Buy split-popover button", but WorldCat isn't in the new popover — it only contains
So 🔴 BLOCKING — Root cause:
Verified working (so you don't need to re-check these):
Non-blocking — orphaned CSS this PR leaves behind. Non-blocking — declared width isn't the rendered width. DESIGN SYSTEMChecked rule-by-rule against ❌ Hover transitions ( .buy-options .buy-option { transition: background-color 0.2s; }
.buy-options .buy-option:hover { background-color: var(--lightest-grey); }Transitions belong on ❌ Deprecated colour aliases (
❌ Hover direction on a dark fill ( ❌ Hover not gated to hover-capable pointers ( ❌ Prices need ❌ Top margin ( ❌ Hardcoded control height.
✅ N/A, checked: ACCESSIBILITY
TESTSGAP — no tests accompany the change. The interesting part is why the crash above survived a green CI run: (Credit where due: SECURITYNo findings. All option links carry OVERALLFOUND ISSUES — 3 blocking, all fixable and none of them design problems with the approach itself:
Also needs a maintainer decision — scope. #12867 is Mek's own open PR (branch
One last note: the sticky left column ( Verified in Docker on the rebased branch: pre-commit and pre-push suites green, edition pages rendered, dropdown exercised in Playwright (Chromium, desktop 1280×800 and Pixel 5) with axe-core. |
|
Pushed a fix for BLOCKER 1 ( Removed the dead block at I deliberately did not try to implement the blue/grey primary-button behaviour that The other two blockers from my review above are untouched and still need decisions rather than code from me:
Also worth knowing, and not your fault: this class of bug is invisible to CI. |
…ed up docker builds
The rebase onto master conflicted only in the generated messages.pot
(25 hunks, all source-reference churn from ~6 weeks of master drift).
Resolved by taking master's version and regenerating with
`scripts/i18n-messages extract`, rather than hand-merging line refs.
Net effect of this PR's own string changes:
- "Buy" gains a databarWork.html reference (the new dropdown label)
- "More" loses its AffiliateLinks.html.jinja reference (details/summary
disclosure removed in favour of a flat list)
- "Buy this book" is now referenced only from databarWork.html
(the duplicated mobile-vendor block in type/edition/view.html is gone)
Also drops a stale `type/work/view.html` reference on "Buy this book"
that master's checked-in .pot carried but its templates no longer
support -- an artifact of master's .pot, not of this PR.
The two [pre-commit.ci] commits on the branch contained only .pot
regeneration and became empty against current master, so the rebase
dropped them. `chore(ci): increase page-admin.css bundlesize maxSize to
28KB` was likewise dropped -- git detected its content already upstream
via 257e08c.
databarWork.html referenced `worldcat_url`, which is not defined in this
template's scope -- the macro is passed `worldcat_links` (plural, a
pre-rendered blob). Repo-wide, `worldcat_url` exists only as the
`Edition.get_worldcat_url()` method in plugins/upstream/models.py. The
expression sat at macro top level, so it evaluated on every render:
GET /books/OL1M -> HTTP 500
NameError: name 'worldcat_url' is not defined
File "openlibrary/macros/databarWork.html", line 12, in __template__
Deleting the block rather than repairing the expression, because the whole
thing is dead code:
- `buy_is_primary` is never read -- no CSS, template, JS or Python
reference anywhere in the repo.
- `_has_digital` is read only on the line that crashes.
- `availability` is independently re-assigned further down, before its
only other use, so removing the top-level binding changes nothing.
Rendered output is therefore unchanged; /books/OL1M, OL2M, OL4M and
OL24218089M all return 200 with this applied.
The block is a leftover from the larger sidebar consolidation in internetarchive#12867
(branch 12826/consolidate-sidebar-cta), which does compute and pass
`worldcat_url` down through LoanStatus/view.html and implements the
blue/grey primary-button state matrix `buy_is_primary` was meant to feed.
Neither half is present in this PR, so reimplementing that behaviour here
would be guesswork; it belongs with the slice that carries ReadButton and
LocateButton.
Note this class of bug is invisible to CI: tests/test_templates.py
parses every macro but never renders one, so a NameError on an undefined
name passes python_tests by construction.
bf027cd to
a64c7b1
Compare
…esize
Two fixes so this ships working rather than with a known regression and a
red check.
1. WorldCat is reachable again from the sidebar CTA
-----------------------------------------------------
The PR removed both `$:worldcat_links` render sites (databarWork.html's
desktop-vendor panel and view.html's mobile-vendor panel) while still
computing `worldcat_link` and passing it into the macro, so it was
received and silently discarded. Net effect: the "find in a library"
affordance disappeared from every book page, contradicting the PR's own
description, which says WorldCat was consolidated INTO the Buy button.
Restored it there, which is what that description promised. WorldcatLink
is emitted as a flat `.buy-option` row matching the affiliate store rows
instead of the old standalone `.cta-section` vendor card, and is rendered
ABOVE the affiliate list so the affiliate commission disclaimer stays
adjacent to the links it actually describes -- WorldCat earns no
commission and should not sit under that notice.
WorldcatLink.html has exactly one caller (view.html -> databarWork), so
restyling it does not affect anything else.
2. bundlesize: 3 failing bundles -> all 24 checks pass
-----------------------------------------------------
`components/read-panel.css` is imported by BOTH page-book.css AND
legacy.css, and legacy.css feeds page-form, page-edit, page-admin,
page-user, page-list-edit and page-plain -- so the buy-dropdown CSS was
duplicated into 7 bundles, 6 of which never render a buy button. That
pushed page-book, page-edit and page-plain over their caps.
Per docs/ai/css.md (raising caps is not among its sanctioned options):
- moved the buy-popover rules into components/buy-popover.css, imported
by page-book.css ONLY, never via legacy.css
- removed CSS this PR orphaned: .desktop-vendor, .mobile-vendor,
.cta-section-title.world-cat-link, and the book-locate-options half of
a shared selector
- removed the `transition` on the hover background, which docs/ai/design.md
forbids outright ("hover state changes are instant")
- removed three long-dead rule sets to make room, as css.md prescribes:
.sponsorship-card (markup deleted by 90d508e "remove sponsorship"),
.check-availability and .check-other-editions (markup gone since internetarchive#2341/
internetarchive#2365). All three verified to have zero non-CSS references repo-wide.
Local `bundlesize`: page-book 16.92KB < 17KB, page-edit 26.72KB < 27KB,
page-plain 26.8KB < 27KB. 24 passed, 0 failed.
Verified with Playwright (Chromium, desktop 1280x800 + Pixel 5): no 500s
across 4 editions and 2 works; the Buy button renders, opens by click,
Enter and Space; Escape closes it and returns focus to the trigger; Tab
reaches every option including WorldCat; the WorldCat row carries a real
worldcat.org/oclc href with rel="noopener noreferrer"; no uncaught JS
errors.
The .pot change is only a reordering of the three existing WorldcatLink
strings, following their new source order -- none added or removed.
|
Pushed two more fixes ( WorldCat is reachable again, inside the Buy popoverThis restores what this PR's own description promised ("consolidates the sidebar WorldCat/library locate links and purchase/affiliate options into the unified Buy split-popover button") — previously both
bundlesize: 3 failing bundles → all 24 checks pass
Following
Local Playwright verificationChromium, desktop 1280×800 and Pixel 5. All passing:
Still yours, and deliberately not touchedI left the design-system items from my review for you rather than rewriting your styling — except the
Two things I confirmed are not yours, so they don't need action here: the |
Closes #12867
Consolidates the sidebar WorldCat/library locate links and purchase/affiliate options into the unified "Buy" split-popover button on the edition and work pages, and removes the legacy sidebar vendor panels completely on desktop and mobile.
Technical
databarWork.htmlto render the "Buy" button popover containing asynchronous store options.AffiliateLinks.html.jinjaandAffiliateLinksLoadingIndicator.htmlto use div containers and render a flat list of stores with full-row clickability.width: 100%) and240pxon desktop..editionCoverleft column sticky on desktop to keep actions visible during scroll.Testing
uv run --with-requirements requirements_test.txt pytest openlibrary/tests/test_templates.pyScreenshot
screen-capture.webm
Stakeholders
@mekarpeles @lokesh