Reader: add footnote popovers

Lacks a "go to" button, but at least shows something instead of nothing
This commit is contained in:
John Factotum
2022-10-21 18:57:26 +00:00
committed by GitHub
parent e74ad4311f
commit 3c05d0a957
3 changed files with 100 additions and 0 deletions
+14
View File
@@ -237,6 +237,20 @@ body {
background-repeat: no-repeat; background-repeat: no-repeat;
background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%2212%22%20r%3D%223%22%2F%3E%3C%2Fsvg%3E'); background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%2212%22%20r%3D%223%22%2F%3E%3C%2Fsvg%3E');
} }
.popover {
background: Canvas;
color: CanvasText;
border-radius: 6px;
box-shadow: 0 0 0 1px rgba(0, 0, 0, .2), 0 0 16px rgba(0, 0, 0, .1), 0 0 32px rgba(0, 0, 0, .1);
}
.popover-arrow-down {
fill: Canvas;
filter: drop-shadow(0 -1px 0 rgba(0, 0, 0, .2));
}
.popover-arrow-up {
fill: Canvas;
filter: drop-shadow(0 1px 0 rgba(0, 0, 0, .2));
}
</style> </style>
<input type="file" id="file-input" hidden> <input type="file" id="file-input" hidden>
<div id="drop-target" class="filter"> <div id="drop-target" class="filter">
+25
View File
@@ -2,6 +2,7 @@
import { View } from './view.js' import { View } from './view.js'
import { createTOCView } from './ui/tree.js' import { createTOCView } from './ui/tree.js'
import { createMenu } from './ui/menu.js' import { createMenu } from './ui/menu.js'
import { createPopover } from './ui/popover.js'
const { ZipReader, BlobReader, TextWriter, BlobWriter } = zip const { ZipReader, BlobReader, TextWriter, BlobWriter } = zip
zip.configure({ useWebWorkers: false }) zip.configure({ useWebWorkers: false })
@@ -119,6 +120,30 @@ const emit = obj => {
if (tocItem?.href) setCurrentHref?.(tocItem.href) if (tocItem?.href) setCurrentHref?.(tocItem.href)
break break
} }
case 'reference': {
const { content, pos: { point, dir } } = obj
const iframe = document.createElement('iframe')
iframe.sandbox = 'allow-same-origin'
iframe.srcdoc = content
iframe.onload = () => {
const doc = iframe.contentDocument
doc.documentElement.style.colorScheme = 'light dark'
doc.body.style.margin = '18px'
}
Object.assign(iframe.style, {
border: '0',
width: '100%',
height: '100%',
})
const { popover, arrow, overlay } = createPopover(300, 250, point, dir)
overlay.style.zIndex = 3
popover.style.zIndex = 3
arrow.style.zIndex = 3
popover.append(iframe)
document.body.append(overlay)
document.body.append(popover)
document.body.append(arrow)
}
} }
} }
+61
View File
@@ -0,0 +1,61 @@
const clamp = (min, max, x) => Math.min(max, Math.max(min, x))
const arrowHeight = 10
const arrowWidth = 20
const radius = 6
const createSVGElement = tag =>
document.createElementNS('http://www.w3.org/2000/svg', tag)
const createArrow = down => {
const h = arrowHeight + 1
const svg = createSVGElement('svg')
svg.setAttribute('width', arrowWidth)
svg.setAttribute('height', arrowHeight)
const polygon = createSVGElement('polygon')
polygon.setAttribute('points', down
? `0 ${h}, ${arrowWidth / 2} 0, ${arrowWidth} ${h}`
: `0 0, ${arrowWidth / 2} ${h}, ${arrowWidth} 0`)
svg.classList.add(down ? 'popover-arrow-down' : 'popover-arrow-up')
svg.append(polygon)
return svg
}
export const createPopover = (width, height, { x, y }, dir) => {
const down = dir === 'down'
const fullHeight = height + arrowHeight
const overlay = document.createElement('div')
Object.assign(overlay.style, {
position: 'absolute',
left: '0',
top: '0',
width: '100vw',
height: '100vh',
})
const arrow = createArrow(down)
Object.assign(arrow.style, {
position: 'absolute',
left: `${clamp(radius, window.innerWidth - arrowWidth - radius,
x - arrowWidth / 2)}px`,
top: `${clamp(0, window.innerHeight - arrowHeight,
down ? y : y - arrowHeight)}px`,
})
const popover = document.createElement('div')
popover.classList.add('popover')
Object.assign(popover.style, {
position: 'absolute',
boxSizing: 'border-box',
overflow: 'hidden',
left: `${clamp(0, window.innerWidth - width, x - width / 2)}px`,
top: `${clamp(0, window.innerHeight - fullHeight,
down ? y + arrowHeight : y - fullHeight)}px`,
width: `${width}px`,
height: `${height}px`,
})
overlay.addEventListener('click', () => {
overlay.parentNode.removeChild(overlay)
arrow.parentNode.removeChild(arrow)
popover.parentNode.removeChild(popover)
})
return { popover, arrow, overlay }
}