Skip to content

Commit

Permalink
OPDS: various stylistic fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
johnfactotum committed Dec 9, 2023
1 parent 59508eb commit 067f2c8
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 57 deletions.
2 changes: 1 addition & 1 deletion src/library.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const uiText = {
acq: {
'http://opds-spec.org/acquisition': _('Download'),
'http://opds-spec.org/acquisition/buy': _('Buy'),
'http://opds-spec.org/acquisition/open-access': _('Free'),
'http://opds-spec.org/acquisition/open-access': _('Download'),
'http://opds-spec.org/acquisition/preview': _('Preview'),
'http://opds-spec.org/acquisition/sample': _('Sample'),
'http://opds-spec.org/acquisition/borrow': _('Borrow'),
Expand Down
83 changes: 56 additions & 27 deletions src/opds/opds.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
overflow-wrap: anywhere;
font-size: 11pt;
font-family: system-ui;
--shade: rgba(0, 0, 0, .1);
--raised: rgba(0, 0, 0, .05);
--pressed: rgba(0, 0, 0, .15);
--shade: rgba(0, 0, 0, .07);
--raised: rgba(0, 0, 0, .1);
--pressed: rgba(0, 0, 0, .2);
}
@media (prefers-color-scheme: dark) {
:root {
--shade: rgba(255, 255, 255, .1);
--raised: rgba(255, 255, 255, .05);
--pressed: rgba(255, 255, 255, .15);
--shade: rgba(255, 255, 255, .15);
--raised: rgba(255, 255, 255, .2);
--pressed: rgba(255, 255, 255, .25);
}
}
a:any-link {
Expand Down Expand Up @@ -245,6 +245,13 @@
display: block;
max-width: 640px;
}
opds-pub-full a:any-link {
text-decoration: underline;
text-decoration-color: color-mix(in hsl, currentcolor, transparent 75%);
}
opds-pub-full a:any-link:hover {
text-decoration-color: currentcolor;
}
opds-pub-full > [slot="details"] table {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
Expand Down Expand Up @@ -272,45 +279,76 @@
margin-inline-end: 2em;
font-size: smaller;
}
button, foliate-menubutton::part(button) {
opds-pub-full > [slot="details"] [role="listitem"] + [role="listitem"] {
margin-block-start: 1em;
}
button {
display: inline-flex;
justify-content: center;
align-items: center;
padding: 12px 24px;
padding: 9px;
font: inherit;
font-weight: 700;
border-radius: 9999px;
border-radius: 6px;
border: 0;
background: none;
}
button:hover {
background: var(--shade);
}
button:active, button[aria-expanded="true"] {
background: var(--raised);
}
button.raised {
background: var(--shade);
}
button:hover, foliate-menubutton::part(button):hover {
button.raised:hover {
background: var(--raised);
}
button:active, foliate-menubutton::part(button):active {
button.raised:active, button.raised[aria-expanded="true"] {
background: var(--pressed);
}
.pill {
border-radius: 9999px;
padding: 12px 24px;
}
opds-pub-full > [slot="actions"] {
display: flex;
flex-wrap: wrap;
gap: 9px;
width: 100%;
margin-top: 1em;
}
opds-pub-full > [slot="actions"] > * {
min-width: min(100%, 8em);
}

/* if first button is "sample", highlight last button */
opds-pub-full > [slot="actions"]:has([data-rel$="sample"]:first-child) > button:not([data-rel$="sample"]):not(:has(~ :not([data-rel$="sample"]))),
opds-pub-full > [slot="actions"]:has([data-rel$="sample"]:first-child) > :not([data-rel$="sample"]):not(:has(~ :not([data-rel$="sample"]))) > button,
opds-pub-full > [slot="actions"]:has([data-rel$="sample"]:first-child) > :not([data-rel$="sample"]):not(:has(~ :not([data-rel$="sample"]))) > foliate-menubutton > button,
/* otherwise, highlight first button */
opds-pub-full > [slot="actions"]:not(:has([data-rel$="sample"]:first-child)) > button:first-child,
opds-pub-full > [slot="actions"]:not(:has([data-rel$="sample"]:first-child)) > *:first-child > button,
opds-pub-full > [slot="actions"]:not(:has([data-rel$="sample"]:first-child)) > *:first-child > foliate-menubutton > button {
color: highlighttext;
--shade: highlight;
--raised: color-mix(in srgb, var(--shade), highlighttext 10%);
--pressed: color-mix(in srgb, var(--shade), transparent 20%);
}
.split-button {
display: flex;
}
.split-button button {
.split-button > button {
flex: 1;
border-start-end-radius: 0;
border-end-end-radius: 0;
}
.split-button foliate-menubutton::part(button) {
.split-button foliate-menubutton > button {
padding: 9px;
border-start-start-radius: 0;
border-end-start-radius: 0;
border-inline-start: 1px solid color-mix(in hsl, currentColor, transparent 85%);;
border-inline-start: 1px solid color-mix(in hsl, currentColor, transparent 75%);
}
foliate-menubutton {
display: flex;
Expand Down Expand Up @@ -338,16 +376,9 @@
text-align: start;
justify-content: start;
font: menu;
background: none;
border-radius: 6px;
padding: 9px;
}
button[role="menuitem"]:hover {
background: var(--raised);
}
button[role="menuitem"]:active {
background: var(--pressed);
}
</style>
<template id="opds-nav">
<style>
Expand Down Expand Up @@ -475,15 +506,13 @@ <h1><a></a></h1>
:host([downloading]) #actions > :not(#downloading) { display: none }
</style>
<div id="header">
<img id="cover">
<h1></h1>
<img id="cover" aria-labelledby="heading">
<h1 id="heading"></h1>
<slot name="authors"></slot>
<div id="actions">
<div id="downloading">
<progress></progress>
<button>
<foliate-symbolic src="/icons/hicolor/scalable/actions/stop-sign-symbolic.svg"></foliate-symbolic>
</button>
<slot name="cancel"></slot>
</div>
<slot name="actions"></slot>
</div>
Expand All @@ -510,7 +539,7 @@ <h1></h1>
<p></p>
<form>
<div id="search-params"></div>
<button></button>
<button class="raised pill"></button>
</form>
</div>
</div>
Expand Down
27 changes: 18 additions & 9 deletions src/opds/opds.js
Original file line number Diff line number Diff line change
Expand Up @@ -185,11 +185,6 @@ customElements.define('opds-pub-full', class extends HTMLElement {
updateHeight()
new ResizeObserver(updateHeight).observe(doc.documentElement)
}

const button = this.#root.querySelector('#downloading button')
button.title = globalThis.uiText.cancel
button.addEventListener('click', () =>
this.dispatchEvent(new Event('cancel-download')))
}
attributeChangedCallback(name, _, val) {
switch (name) {
Expand Down Expand Up @@ -370,7 +365,7 @@ const renderContributor = async (contributor, baseURL) => {
if (!contributor) return
const as = await Promise.all([contributor ?? []].flat().map(async contributor => {
const a = renderLinkedObject(contributor, baseURL)
a.innerText = typeof contributor === 'string' ? contributor
a.textContent = typeof contributor === 'string' ? contributor
: await renderLanguageMap(contributor.name)
return a
}))
Expand All @@ -383,14 +378,19 @@ const renderAcquisitionButton = async (rel, links, callback) => {
const price = priceData ? await globalThis.formatPrice(priceData) : null

const button = document.createElement('button')
button.innerText = price ? `${label} · ${price}` : label
button.classList.add('raised', 'pill')
button.textContent = price ? `${label} · ${price}` : label
button.onclick = () => callback(links[0].href)
button.dataset.rel = rel
if (links.length === 1) return button
else {
const menuButton = document.createElement('foliate-menubutton')
const menuButtonButton = document.createElement('button')
menuButtonButton.classList.add('raised', 'pill')
menuButton.append(menuButtonButton)
const icon = document.createElement('foliate-symbolic')
icon.setAttribute('src', '/icons/hicolor/scalable/actions/pan-down-symbolic.svg')
menuButton.append(icon)
menuButtonButton.append(icon)
const menu = document.createElement('foliate-menu')
menu.slot = 'menu'
menuButton.append(menu)
Expand All @@ -411,6 +411,7 @@ const renderAcquisitionButton = async (rel, links, callback) => {
const div = document.createElement('div')
div.classList.add('split-button')
div.replaceChildren(button, menuButton)
div.dataset.rel = rel
return div
}
}
Expand Down Expand Up @@ -526,14 +527,22 @@ const renderPublication = async (pub, baseURL) => {
const item = document.createElement('opds-pub-full')
const token = new Date() + Math.random()
entryMap.set(token, new WeakRef(item))
item.addEventListener('cancel-download', () => emit({ type: 'cancel', token }))
const download = href => {
href = resolveURL(href, baseURL)
item.setAttribute('downloading', '')
item.removeAttribute('progress')
emit({ type: 'download', href, token })
}

const cancelButton = document.createElement('button')
cancelButton.slot = 'cancel'
cancelButton.title = globalThis.uiText.cancel
item.append(cancelButton)
const icon = document.createElement('foliate-symbolic')
icon.setAttribute('src', '/icons/hicolor/scalable/actions/stop-sign-symbolic.svg')
cancelButton.append(icon)
cancelButton.addEventListener('click', () => emit({ type: 'cancel', token }))

const src = resolveURL(pub.images?.[0]?.href, baseURL)
if (src) item.setAttribute('image', src)

Expand Down
42 changes: 22 additions & 20 deletions src/opds/widgets.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,14 +107,15 @@ customElements.define('foliate-menu', class extends HTMLElement {

customElements.define('foliate-menubutton', class extends HTMLElement {
#root = this.attachShadow({ mode: 'open' })
#button = document.createElement('button')
#button
#menu
#ariaExpandedObserver = new MutationObserver(list => {
for (const { target } of list)
target.dispatchEvent(new Event('aria-expanded'))
})
#onBlur = () => this.#button.ariaExpanded = 'false'
#onBlur = () => this.#button ? this.#button.ariaExpanded = 'false' : null
#onClick = e => {
if (!this.#button) return
const target = e.composedPath()[0]
if (!this.contains(target) && !this.#button.contains(target) && !this.#menu.contains(target)) {
this.#button.setAttribute('aria-expanded', 'false')
Expand All @@ -126,26 +127,27 @@ customElements.define('foliate-menubutton', class extends HTMLElement {
sheet.replaceSync(':host { position: relative }')
this.#root.adoptedStyleSheets = [sheet]

this.#root.append(this.#button)
this.#button.ariaExpanded = 'false'
this.#button.ariaHasPopup = 'menu'
this.#button.part = 'button'

const slot = document.createElement('slot')
this.#button.append(slot)
this.#root.append(slot)
slot.addEventListener('slotchange', e => {
this.#button = e.target.assignedElements()[0]
if (!this.#button) return
this.#button.ariaExpanded = 'false'
this.#button.ariaHasPopup = 'menu'

this.#ariaExpandedObserver.observe(this.#button,
{ attributes: true, attributeFilter: ['aria-expanded'] })
this.#button.addEventListener('click', () => {
this.#button.ariaExpanded =
this.#button.ariaExpanded === 'true' ? 'false' : 'true'
})
this.#button.addEventListener('aria-expanded', () => {
if (!this.#menu) return
if (this.#button.ariaExpanded === 'true') {
this.#menu.hidden = false
this.#menu.focus()
} else this.#menu.hidden = true
this.#ariaExpandedObserver.observe(this.#button,
{ attributes: true, attributeFilter: ['aria-expanded'] })
this.#button.addEventListener('click', () => {
this.#button.ariaExpanded =
this.#button.ariaExpanded === 'true' ? 'false' : 'true'
})
this.#button.addEventListener('aria-expanded', () => {
if (!this.#menu) return
if (this.#button.ariaExpanded === 'true') {
this.#menu.hidden = false
this.#menu.focus()
} else this.#menu.hidden = true
})
})

const menuSlot = document.createElement('slot')
Expand Down

0 comments on commit 067f2c8

Please sign in to comment.