diff --git a/bundlesize.config.json b/bundlesize.config.json
index d4e46bab4bd..afa5cda2da6 100644
--- a/bundlesize.config.json
+++ b/bundlesize.config.json
@@ -58,8 +58,7 @@
},
{
"path": "static/build/css/page-admin.css",
- "maxSize": "27KB"
-
+ "maxSize": "28KB"
},
{
"path": "static/build/css/page-book.css",
diff --git a/docker/Dockerfile.olbase b/docker/Dockerfile.olbase
index e20dfd45490..1bdb76cf21f 100644
--- a/docker/Dockerfile.olbase
+++ b/docker/Dockerfile.olbase
@@ -85,4 +85,5 @@ RUN npm ci --no-audit
COPY --chown=openlibrary:openlibrary . /openlibrary
# run make to initialize git submodules, build css and js files
RUN ln -s vendor/infogami/infogami infogami \
+ && touch node_modules \
&& make
diff --git a/openlibrary/i18n/messages.pot b/openlibrary/i18n/messages.pot
index a5c7150e043..28697e624d8 100644
--- a/openlibrary/i18n/messages.pot
+++ b/openlibrary/i18n/messages.pot
@@ -4344,7 +4344,7 @@ msgstr ""
msgid "Provider Name"
msgstr ""
-#: books/edit/edition.html
+#: books/edit/edition.html databarWork.html
msgid "Buy"
msgstr ""
@@ -4765,7 +4765,7 @@ msgid ""
" page for every book ever published."
msgstr ""
-#: AffiliateLinks.html.jinja home/about.html search/work_search_facets.html
+#: home/about.html search/work_search_facets.html
msgid "More"
msgstr ""
@@ -7140,10 +7140,6 @@ msgstr ""
msgid "ISBNs"
msgstr ""
-#: databarWork.html type/edition/view.html type/work/view.html
-msgid "Buy this book"
-msgstr ""
-
#: type/edition/view.html type/work/view.html
msgid "Book Details"
msgstr ""
@@ -8385,6 +8381,10 @@ msgstr ""
msgid "View Volume %(num)d"
msgstr ""
+#: databarWork.html
+msgid "Buy this book"
+msgstr ""
+
#: openlibrary/core/bookshelves.py
msgid "[Record deleted]"
msgstr ""
diff --git a/openlibrary/macros/AffiliateLinks.html.jinja b/openlibrary/macros/AffiliateLinks.html.jinja
index 164f619505d..5e722130bf2 100644
--- a/openlibrary/macros/AffiliateLinks.html.jinja
+++ b/openlibrary/macros/AffiliateLinks.html.jinja
@@ -1,31 +1,24 @@
{% macro affiliate_link(store) %}
-
-
+ {{ store.name }}
- {% if store.price %}
-
- {{ store.price }}{{ store.price_note }}
- {% endif %}
-
+ rel="noopener noreferrer">
+ {{ store.name }}
+ {% if store.price %}
+ {{ store.price }}{{ store.price_note }}
+ {% endif %}
+
+
{% endmacro %}
-
-
+
+
{% for store in primary_stores %}{{ affiliate_link(store) | safe }}{% endfor %}
- {% if more_stores %}
-
-
-
- {{ _("More") }}
-
- {% for store in more_stores %}{{ affiliate_link(store) | safe }}{% endfor %}
-
-
-
- {% endif %}
-
-
+ {% for store in more_stores %}{{ affiliate_link(store) | safe }}{% endfor %}
+
+
{{ _("When you buy books using these links the Internet Archive may earn a small commission.") | safe }}
-
+
diff --git a/openlibrary/macros/AffiliateLinksLoadingIndicator.html b/openlibrary/macros/AffiliateLinksLoadingIndicator.html
index 6ef6ed565ff..9c00d56232e 100644
--- a/openlibrary/macros/AffiliateLinksLoadingIndicator.html
+++ b/openlibrary/macros/AffiliateLinksLoadingIndicator.html
@@ -3,6 +3,6 @@
isbn_str = isbn or ''
asin_str = asin or ''
prices_str = 'true' if prices else 'false'
-
+
$:macros.LoadingIndicator(_("Fetching prices"), additional_classes="affiliate-links-loading")
-
+
diff --git a/openlibrary/macros/LoanStatus.html b/openlibrary/macros/LoanStatus.html
index 253422ec1ab..b53ab07b8ce 100644
--- a/openlibrary/macros/LoanStatus.html
+++ b/openlibrary/macros/LoanStatus.html
@@ -1,4 +1,4 @@
-$def with (doc, work_key=None, listen=True, allow_expensive_availability_check=False, secondary_action=False, check_loan_status=False, user_lists=None, post='', is_book_page=False, analytics_override=None, lending_state=None)
+$def with (doc, work_key=None, listen=True, allow_expensive_availability_check=False, secondary_action=False, check_loan_status=False, user_lists=None, is_book_page=False, analytics_override=None, lending_state=None)
$# Takes following parameters:
$# * doc - Can be a Work, Edition, or solr dict.
$# * listen - whether to display listen button
@@ -167,8 +167,6 @@
$else:
$:macros.NotInLibrary(None, analytics_attr)
-$:post
-
$if query_param('debug'):
$ loanstatus_end_time = time() - loanstatus_start_time
get_waiting_loan_for(ocaid) took $("%.2f" % waiting_loan_total_time) seconds
$# detect-missing-i18n-skip-line
diff --git a/openlibrary/macros/databarWork.html b/openlibrary/macros/databarWork.html
index dbf7166bf55..1847ef44ca1 100644
--- a/openlibrary/macros/databarWork.html
+++ b/openlibrary/macros/databarWork.html
@@ -2,6 +2,11 @@
$ viewbook = "//%s/stream/XXX?ref=ol" % bookreader_host()
+$# 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)
+
-
-
-
- $:worldcat_links
-
-
-
$_('Buy this book')
- $:affiliate_links
-
-
-
diff --git a/openlibrary/templates/type/edition/view.html b/openlibrary/templates/type/edition/view.html
index e4f3580b374..91223b313c9 100644
--- a/openlibrary/templates/type/edition/view.html
+++ b/openlibrary/templates/type/edition/view.html
@@ -306,19 +306,6 @@
-
-
$ seen = set()
$if previews and any([len(e.languages) for e in previews]):
diff --git a/static/css/components/read-panel.css b/static/css/components/read-panel.css
index 80d9966b711..3240609a2d9 100644
--- a/static/css/components/read-panel.css
+++ b/static/css/components/read-panel.css
@@ -130,20 +130,6 @@ ul.ebook-download-options li {
margin: 5px 0;
}
-.buy-options-table {
- line-height: 2em;
-}
-
-.buy-options-table .more {
- margin-left: 0;
- cursor: pointer;
-}
-
-.buy-options-table + small {
- display: block;
- margin-top: 10px;
-}
-
.cta-section-title.world-cat-link {
margin-top: 0;
}
@@ -286,3 +272,111 @@ ul.ebook-download-options li {
/* stylelint-enable selector-max-specificity */
/* stylelint-enable max-nesting-depth */
}
+
+/* Buy popover: full-width trigger button */
+.buy-popover {
+ display: block;
+ width: 100%;
+ margin-top: var(--spacing-stack-xs);
+}
+
+/* Buy options popover content */
+.buy-options {
+ box-sizing: border-box;
+ width: 100%;
+ background-color: var(--white);
+ border-radius: var(--border-radius-overlay);
+}
+
+@media only screen and (min-width: 768px) {
+ .buy-options {
+ width: 240px;
+ }
+}
+
+.buy-options .buy-option {
+ transition: background-color 0.2s;
+}
+
+.buy-options .buy-option:hover {
+ background-color: var(--lightest-grey);
+}
+
+.buy-options .buy-option__link {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: var(--spacing-inset-sm) var(--spacing-inset-md);
+ color: var(--dark-grey);
+ text-decoration: none;
+ font-size: var(--font-size-body-medium);
+}
+
+.buy-options .buy-option__price {
+ font-size: var(--font-size-label-medium);
+ color: var(--accessible-grey);
+}
+
+/* Disclaimer with top horizontal border */
+.buy-options .buy-options__disclaimer {
+ display: block;
+ padding: var(--spacing-inset-sm) var(--spacing-inset-md);
+ border-top: 1px solid var(--lighter-grey);
+ color: var(--accessible-grey);
+ font-size: var(--font-size-label-medium);
+ line-height: 1.4;
+}
+
+.buy-options .buy-options__disclaimer a {
+ color: var(--link-blue);
+ text-decoration: underline;
+}
+
+/* Buy button custom styling (single button with left icon and right arrow) */
+.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);
+}
+
+.cta-btn--buy .btn-icon.cart {
+ position: absolute;
+ left: 12px;
+}
+
+.cta-btn--buy .btn-label {
+ padding: 0;
+}
+
+.cta-btn--buy .arrow-down {
+ position: absolute;
+ right: 0;
+ top: 0;
+ width: 32px;
+ height: 100%;
+ border-left: 1px solid var(--grey);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.cta-btn--buy .arrow-down::after {
+ content: "";
+ display: block;
+ width: 23px;
+ height: 23px;
+ background: url(/static/images/icons/icon_dropit.png) no-repeat center;
+ background-position: 0;
+ background-size: 45px;
+ filter: brightness(0) invert(1);
+}
diff --git a/static/css/components/work.css b/static/css/components/work.css
index 3a2a7d1a285..27d77d17584 100644
--- a/static/css/components/work.css
+++ b/static/css/components/work.css
@@ -202,6 +202,9 @@ div.editionTools p {
width: var(--sidebar-width);
margin-right: 1.5em;
margin-bottom: 0;
+ position: sticky;
+ top: 20px;
+ align-self: flex-start;
}
div.editionAbout {
flex: 1;